1 const char loaders_rcs[] = "$Id: loaders.c,v 1.6 2001/05/23 12:27:33 oes Exp $";
2 /*********************************************************************
4 * File : $Source: /cvsroot/ijbswa/current/loaders.c,v $
6 * Purpose : Functions to load and unload the various
7 * configuration files. Also contains code to manage
8 * the list of active loaders, and to automatically
9 * unload files that are no longer in use.
11 * Copyright : Written by and Copyright (C) 2001 the SourceForge
12 * IJBSWA team. http://ijbswa.sourceforge.net
14 * Based on the Internet Junkbuster originally written
15 * by and Copyright (C) 1997 Anonymous Coders and
16 * Junkbusters Corporation. http://www.junkbusters.com
18 * This program is free software; you can redistribute it
19 * and/or modify it under the terms of the GNU General
20 * Public License as published by the Free Software
21 * Foundation; either version 2 of the License, or (at
22 * your option) any later version.
24 * This program is distributed in the hope that it will
25 * be useful, but WITHOUT ANY WARRANTY; without even the
26 * implied warranty of MERCHANTABILITY or FITNESS FOR A
27 * PARTICULAR PURPOSE. See the GNU General Public
28 * License for more details.
30 * The GNU General Public License should be included with
31 * this file. If not, you can view it at
32 * http://www.gnu.org/copyleft/gpl.html
33 * or write to the Free Software Foundation, Inc., 59
34 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 * Revision 1.6 2001/05/23 12:27:33 oes
40 * Fixed ugly indentation of my last changes
42 * Revision 1.5 2001/05/23 10:39:05 oes
43 * - Added support for escaping the comment character
44 * in config files by a backslash
45 * - Added support for line continuation in config
47 * - Fixed a buffer overflow bug with long config lines
49 * Revision 1.4 2001/05/22 18:56:28 oes
52 * Revision 1.3 2001/05/20 01:21:20 jongfoster
53 * Version 2.9.4 checkin.
54 * - Merged popupfile and cookiefile, and added control over PCRS
55 * filtering, in new "permissionsfile".
56 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
57 * file error you now get a message box (in the Win32 GUI) rather
58 * than the program exiting with no explanation.
59 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
61 * - Removed tabs from "config"
62 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
63 * - Bumped up version number.
65 * Revision 1.2 2001/05/17 23:01:01 oes
66 * - Cleaned CRLF's from the sources and related files
68 * Revision 1.1.1.1 2001/05/15 13:58:59 oes
69 * Initial import of version 2.9.3 source tree
72 *********************************************************************/
79 #include <sys/types.h>
101 #ifndef SPLIT_PROXY_ARGS
103 #include "showargs.h"
104 #endif /* ndef SPLIT_PROXY_ARGS */
106 const char loaders_h_rcs[] = LOADERS_H_VERSION;
108 /* Fix a problem with Solaris. There should be no effect on other
110 * Solaris's isspace() is a macro which uses it's argument directly
111 * as an array index. Therefore we need to make sure that high-bit
112 * characters generate +ve values, and ideally we also want to make
113 * the argument match the declared parameter type of "int".
115 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
119 * Currently active files.
120 * These are also entered in the main linked list of files.
122 static struct file_list *current_blockfile = NULL;
123 static struct file_list *current_permissions_file = NULL;
124 static struct file_list *current_forwardfile = NULL;
127 static struct file_list *current_aclfile = NULL;
128 #endif /* def ACL_FILES */
130 #ifdef USE_IMAGE_LIST
131 static struct file_list *current_imagefile = NULL;
132 #endif /* def USE_IMAGE_LIST */
135 static struct file_list *current_trustfile = NULL;
136 #endif /* def TRUST_FILES */
139 static struct file_list *current_re_filterfile = NULL;
140 #endif /* def PCRS */
143 static int create_url_spec(struct url_spec * url, char * buf);
146 /*********************************************************************
150 * Description : Basically a mark and sweep garbage collector, it is run
151 * (by the parent thread) every once in a while to reclaim memory.
153 * It uses a mark and sweep strategy:
154 * 1) mark all files as inactive
156 * 2) check with each client:
157 * if it is active, mark its files as active
158 * if it is inactive, free its resources
160 * 3) free the resources of all of the files that
161 * are still marked as inactive (and are obsolete).
163 * N.B. files that are not obsolete don't have an unloader defined.
169 *********************************************************************/
172 struct file_list *fl, *nfl;
173 struct client_state *csp, *ncsp;
175 /* clear all of the file's active flags */
176 for ( fl = files->next; NULL != fl; fl = fl->next )
181 for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
185 /* mark this client's files as active */
188 * Always have a configuration file.
189 * (Also note the slightly non-standard extra
192 ncsp->config->config_file_list->active = 1;
194 if (ncsp->blist) /* block files */
196 ncsp->blist->active = 1;
199 if (ncsp->permissions_list) /* permissions files */
201 ncsp->permissions_list->active = 1;
204 if (ncsp->flist) /* forward files */
206 ncsp->flist->active = 1;
210 if (ncsp->alist) /* acl files */
212 ncsp->alist->active = 1;
214 #endif /* def ACL_FILES */
216 #ifdef USE_IMAGE_LIST
217 if (ncsp->ilist) /* image files */
219 ncsp->ilist->active = 1;
221 #endif /* def USE_IMAGE_LIST */
224 if (ncsp->rlist) /* perl re files */
226 ncsp->rlist->active = 1;
228 #endif /* def PCRS */
231 if (ncsp->tlist) /* trust files */
233 ncsp->tlist->active = 1;
235 #endif /* def TRUST_FILES */
240 /* this client one is not active, release its resources */
241 csp->next = ncsp->next;
243 freez(ncsp->ip_addr_str);
244 freez(ncsp->referrer);
245 freez(ncsp->x_forwarded);
246 freez(ncsp->ip_addr_str);
247 freez(ncsp->iob->buf);
249 free_http_request(ncsp->http);
251 destroy_list(ncsp->headers);
252 destroy_list(ncsp->cookie_list);
260 #endif /* def STATISTICS */
266 for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
268 if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
270 fl->next = nfl->next;
272 (nfl->unloader)(nfl->f);
274 #ifndef SPLIT_PROXY_ARGS
275 freez(nfl->proxy_args);
276 #endif /* ndef SPLIT_PROXY_ARGS */
278 freez(nfl->filename);
287 /*********************************************************************
289 * Function : create_url_spec
291 * Description : Creates a "url_spec" structure from a string.
292 * When finished, free with unload_url().
295 * 1 : url = Target url_spec to be filled in. Must be
296 * zeroed out before the call (e.g. using zalloc).
297 * 2 : buf = Source pattern, null terminated. NOTE: The
298 * contents of this buffer are destroyed by this
299 * function. If this function succeeds, the
300 * buffer is copied to url->spec. If this
301 * function fails, the contents of the buffer
304 * Returns : 0 => Ok, everything else is an error.
306 *********************************************************************/
307 static int create_url_spec(struct url_spec * url, char * buf)
310 struct url_spec tmp_url[1];
312 /* paranoia - should never happen. */
313 if ((url == NULL) || (buf == NULL))
318 /* save a copy of the orignal specification */
319 if ((url->spec = strdup(buf)) == NULL)
324 if ((p = strchr(buf, '/')))
326 if (NULL == (url->path = strdup(p)))
331 url->pathlen = strlen(url->path);
345 if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
352 sprintf(rebuf, "^(%s)", url->path);
354 errcode = regcomp(url->preg, rebuf,
355 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
360 url->preg, buf, sizeof(buf));
364 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
375 if ((p = strchr(buf, ':')) == NULL)
385 if ((url->domain = strdup(buf)) == NULL)
391 #endif /* def REGEX */
395 /* split domain into components */
397 *tmp_url = dsplit(url->domain);
398 url->dbuf = tmp_url->dbuf;
399 url->dcnt = tmp_url->dcnt;
400 url->dvec = tmp_url->dvec;
406 /*********************************************************************
408 * Function : unload_url
410 * Description : Called from the "unloaders". Freez the url
411 * structure elements.
414 * 1 : url = pointer to a url_spec structure.
418 *********************************************************************/
419 static void unload_url(struct url_spec *url)
421 if (url == NULL) return;
440 /*********************************************************************
442 * Function : unload_aclfile
444 * Description : Unloads an aclfile.
447 * 1 : f = the data structure associated with the aclfile.
451 *********************************************************************/
452 static void unload_aclfile(void *f)
454 struct access_control_list *b = (struct access_control_list *)f;
455 if (b == NULL) return;
457 unload_aclfile(b->next);
462 #endif /* def ACL_FILES */
464 /*********************************************************************
466 * Function : unload_blockfile
468 * Description : Unloads a blockfile.
471 * 1 : f = the data structure associated with the blockfile.
475 *********************************************************************/
476 static void unload_blockfile(void *f)
478 struct block_spec *b = (struct block_spec *)f;
479 if (b == NULL) return;
481 unload_blockfile(b->next);
490 #ifdef USE_IMAGE_LIST
491 /*********************************************************************
493 * Function : unload_imagefile
495 * Description : Unloads an imagefile.
498 * 1 : f = the data structure associated with the imagefile.
502 *********************************************************************/
503 static void unload_imagefile(void *f)
505 struct block_spec *b = (struct block_spec *)f;
506 if (b == NULL) return;
508 unload_imagefile(b->next);
515 #endif /* def USE_IMAGE_LIST */
518 /*********************************************************************
520 * Function : unload_permissions_file
522 * Description : Unloads a permissions file.
525 * 1 : file_data = the data structure associated with the
530 *********************************************************************/
531 static void unload_permissions_file(void *file_data)
533 struct permissions_spec * next;
534 struct permissions_spec * cur = (struct permissions_spec *)file_data;
538 unload_url(cur->url);
547 /*********************************************************************
549 * Function : unload_trustfile
551 * Description : Unloads a trustfile.
554 * 1 : f = the data structure associated with the trustfile.
558 *********************************************************************/
559 static void unload_trustfile(void *f)
561 struct block_spec *b = (struct block_spec *)f;
562 if (b == NULL) return;
564 unload_trustfile(b->next);
571 #endif /* def TRUST_FILES */
574 /*********************************************************************
576 * Function : unload_forwardfile
578 * Description : Unloads a forwardfile.
581 * 1 : f = the data structure associated with the forwardfile.
585 *********************************************************************/
586 static void unload_forwardfile(void *f)
588 struct forward_spec *b = (struct forward_spec *)f;
589 if (b == NULL) return;
591 unload_forwardfile(b->next);
595 freez(b->gw->gateway_host);
596 freez(b->gw->forward_host);
604 /*********************************************************************
606 * Function : unload_re_filterfile
608 * Description : Unload the re_filter list.
611 * 1 : f = the data structure associated with the filterfile.
615 *********************************************************************/
616 static void unload_re_filterfile(void *f)
619 struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
621 if (b == NULL) return;
623 destroy_list(b->patterns);
625 joblist = b->joblist;
626 while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
631 #endif /* def PCRS */
634 /*********************************************************************
636 * Function : check_file_changed
638 * Description : Helper function to check if a file needs reloading.
639 * If "current" is still current, return it. Otherwise
640 * allocates a new (zeroed) "struct file_list", fills
641 * in the disk file name and timestamp, and returns it.
644 * 1 : current = The file_list currently being used - will
645 * be checked to see if it is out of date.
646 * May be NULL (which is treated as out of
648 * 2 : filename = Name of file to check.
649 * 3 : newfl = New file list. [Output only]
650 * This will be set to NULL, OR a struct
651 * file_list newly allocated on the
652 * heap, with the filename and lastmodified
653 * fields filled, standard header giving file
654 * name in proxy_args, and all others zeroed.
655 * (proxy_args is only filled in if !defined
656 * SPLIT_PROXY_ARGS and !suppress_blocklists).
658 * Returns : If file unchanged: 0 (and sets newfl == NULL)
659 * If file changed: 1 and sets newfl != NULL
660 * On error: 1 and sets newfl == NULL
662 *********************************************************************/
663 int check_file_changed(const struct file_list * current,
664 const char * filename,
665 struct file_list ** newfl)
667 struct file_list *fs;
668 struct stat statbuf[1];
672 if (stat(filename, statbuf) < 0)
674 /* Error, probably file not found. */
679 && (current->lastmodified == statbuf->st_mtime)
680 && (0 == strcmp(current->filename, filename)))
685 fs = (struct file_list *)zalloc(sizeof(struct file_list));
689 /* Out of memory error */
693 fs->filename = strdup(filename);
694 fs->lastmodified = statbuf->st_mtime;
696 if (fs->filename == NULL)
698 /* Out of memory error */
703 #ifndef SPLIT_PROXY_ARGS
704 if (!suppress_blocklists)
706 char * p = html_encode(filename);
709 fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
710 fs->proxy_args = strsav(fs->proxy_args, p);
711 fs->proxy_args = strsav(fs->proxy_args,
712 "' contains the following patterns</h2>\n");
715 fs->proxy_args = strsav(fs->proxy_args, "<pre>");
717 #endif /* ndef SPLIT_PROXY_ARGS */
724 /*********************************************************************
726 * Function : read_config_line
728 * Description : Read a single non-empty line from a file and return
729 * it. Trims comments, leading and trailing whitespace
730 * and respects escaping of newline and comment char.
731 * Also writes the file to fs->proxy_args.
734 * 1 : buf = Buffer to use.
735 * 2 : buflen = Size of buffer in bytes.
736 * 3 : fp = File to read from
737 * 4 : fs = File will be written to fs->proxy_args. May
738 * be NULL to disable this feature.
740 * Returns : NULL on EOF or error
741 * Otherwise, returns buf.
743 *********************************************************************/
744 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
747 char linebuf[BUFSIZ];
752 while (fgets(linebuf, sizeof(linebuf), fp))
754 #ifndef SPLIT_PROXY_ARGS
755 if (fs && !suppress_blocklists)
757 char *html_line = html_encode(linebuf);
758 if (html_line != NULL)
760 fs->proxy_args = strsav(fs->proxy_args, html_line);
763 fs->proxy_args = strsav(fs->proxy_args, "<br>");
765 #endif /* ndef SPLIT_PROXY_ARGS */
767 /* Trim off newline */
768 if ((p = strpbrk(linebuf, "\r\n")) != NULL)
773 /* Line continuation? Trim escape and set flag. */
774 if ((p != linebuf) && (*--p == '\\'))
780 /* If there's a comment char.. */
781 if ((p = strpbrk(linebuf, "#")) != NULL)
783 /* ..and it's escaped, left-shift the line over the escape. */
784 if ((p != linebuf) && (*(p-1) == '\\'))
787 while ((*q++ = *p++) != '\0') /* nop */;
789 /* Else, chop off the rest of the line */
796 /* Trim leading whitespace */
798 while (*p && ijb_isspace(*p))
805 /* There is something other than whitespace on the line. */
807 /* Move the data to the start of buf */
810 /* strcpy that can cope with overlap. */
812 while ((*q++ = *p++) != '\0')
818 /* Trim trailing whitespace */
819 p = linebuf + strlen(linebuf) - 1;
822 * Note: the (p >= linebuf) below is paranoia, it's not really needed.
823 * When p == linebuf then ijb_isspace(*p) will be false and we'll drop
826 while ((p >= linebuf) && ijb_isspace(*p))
832 /* More paranoia. This if statement is always true. */
835 strncat(buf, linebuf, buflen - strlen(buf));
855 /*********************************************************************
857 * Function : load_aclfile
859 * Description : Read and parse an aclfile and add to files list.
862 * 1 : csp = Current client state (buffers, headers, etc...)
864 * Returns : 0 => Ok, everything else is an error.
866 *********************************************************************/
867 int load_aclfile(struct client_state *csp)
870 char buf[BUFSIZ], *v[3], *p;
872 struct access_control_list *a, *bl;
873 struct file_list *fs;
875 if (!check_file_changed(current_aclfile, csp->config->aclfile, &fs))
877 /* No need to load */
880 csp->alist = current_aclfile;
886 goto load_aclfile_error;
889 fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
894 goto load_aclfile_error;
897 fp = fopen(csp->config->aclfile, "r");
901 goto load_aclfile_error;
904 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
906 i = ssplit(buf, " \t", v, SZ(v), 1, 1);
908 /* allocate a new node */
909 a = (struct access_control_list *) zalloc(sizeof(*a));
917 goto load_aclfile_error;
920 /* add it to the list */
927 if (acl_addr(v[2], a->dst) < 0)
929 goto load_aclfile_error;
934 if (acl_addr(v[1], a->src) < 0)
936 goto load_aclfile_error;
940 if (strcmpic(p, "permit") == 0)
942 a->action = ACL_PERMIT;
946 if (strcmpic(p, "deny") == 0)
948 a->action = ACL_DENY;
954 goto load_aclfile_error;
960 #ifndef SPLIT_PROXY_ARGS
961 if (!suppress_blocklists)
963 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
965 #endif /* ndef SPLIT_PROXY_ARGS */
969 current_aclfile->unloader = unload_aclfile;
972 fs->next = files->next;
974 current_aclfile = fs;
984 log_error(LOG_LEVEL_ERROR, "can't load access control list %s: %E",
985 csp->config->aclfile);
989 #endif /* def ACL_FILES */
992 /*********************************************************************
994 * Function : load_blockfile
996 * Description : Read and parse a blockfile and add to files list.
999 * 1 : csp = Current client state (buffers, headers, etc...)
1001 * Returns : 0 => Ok, everything else is an error.
1003 *********************************************************************/
1004 int load_blockfile(struct client_state *csp)
1008 struct block_spec *b, *bl;
1009 char buf[BUFSIZ], *p, *q;
1011 struct file_list *fs;
1013 if (!check_file_changed(current_blockfile, csp->config->blockfile, &fs))
1015 /* No need to load */
1018 csp->blist = current_blockfile;
1024 goto load_blockfile_error;
1027 fs->f = bl = (struct block_spec *) zalloc(sizeof(*bl));
1030 goto load_blockfile_error;
1033 if ((fp = fopen(csp->config->blockfile, "r")) == NULL)
1035 goto load_blockfile_error;
1038 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1047 while ((*p++ = *q++))
1053 /* skip lines containing only ~ */
1059 /* allocate a new node */
1060 if ((b = zalloc(sizeof(*b))) == NULL)
1063 goto load_blockfile_error;
1066 /* add it to the list */
1072 /* Save the URL pattern */
1073 if (create_url_spec(b->url, buf))
1076 goto load_blockfile_error;
1082 #ifndef SPLIT_PROXY_ARGS
1083 if (!suppress_blocklists)
1085 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1087 #endif /* ndef SPLIT_PROXY_ARGS */
1089 /* the old one is now obsolete */
1090 if (current_blockfile)
1092 current_blockfile->unloader = unload_blockfile;
1095 fs->next = files->next;
1097 current_blockfile = fs;
1106 load_blockfile_error:
1107 log_error(LOG_LEVEL_ERROR, "can't load blockfile '%s': %E", csp->config->blockfile);
1113 #ifdef USE_IMAGE_LIST
1114 /*********************************************************************
1116 * Function : load_imagefile
1118 * Description : Read and parse an imagefile and add to files list.
1121 * 1 : csp = Current client state (buffers, headers, etc...)
1123 * Returns : 0 => Ok, everything else is an error.
1125 *********************************************************************/
1126 int load_imagefile(struct client_state *csp)
1130 struct block_spec *b, *bl;
1131 char buf[BUFSIZ], *p, *q;
1133 struct file_list *fs;
1135 if (!check_file_changed(current_imagefile, csp->config->imagefile, &fs))
1137 /* No need to load */
1140 csp->ilist = current_imagefile;
1146 goto load_imagefile_error;
1149 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1152 goto load_imagefile_error;
1155 if ((fp = fopen(csp->config->imagefile, "r")) == NULL)
1157 goto load_imagefile_error;
1160 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1169 while ((*p++ = *q++))
1175 /* skip lines containing only ~ */
1181 /* allocate a new node */
1182 if ((b = zalloc(sizeof(*b))) == NULL)
1185 goto load_imagefile_error;
1188 /* add it to the list */
1194 /* Save the URL pattern */
1195 if (create_url_spec(b->url, buf))
1198 goto load_imagefile_error;
1204 #ifndef SPLIT_PROXY_ARGS
1205 if (!suppress_blocklists)
1207 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1209 #endif /* ndef SPLIT_PROXY_ARGS */
1211 /* the old one is now obsolete */
1212 if (current_imagefile)
1214 current_imagefile->unloader = unload_imagefile;
1217 fs->next = files->next;
1219 current_imagefile = fs;
1228 load_imagefile_error:
1229 log_error(LOG_LEVEL_ERROR, "can't load imagefile '%s': %E", csp->config->imagefile);
1233 #endif /* def USE_IMAGE_LIST */
1236 /*********************************************************************
1238 * Function : load_permissions_file
1240 * Description : Read and parse a permissions file and add to files
1244 * 1 : csp = Current client state (buffers, headers, etc...)
1246 * Returns : 0 => Ok, everything else is an error.
1248 *********************************************************************/
1249 int load_permissions_file(struct client_state *csp)
1253 struct permissions_spec *b, *bl;
1254 char buf[BUFSIZ], *p, *q;
1256 struct file_list *fs;
1259 if (!check_file_changed(current_permissions_file, csp->config->permissions_file, &fs))
1261 /* No need to load */
1264 csp->permissions_list = current_permissions_file;
1270 goto load_permissions_error;
1273 fs->f = bl = (struct permissions_spec *)zalloc(sizeof(*bl));
1276 goto load_permissions_error;
1279 if ((fp = fopen(csp->config->permissions_file, "r")) == NULL)
1281 goto load_permissions_error;
1286 * default_permissions is set in this file.
1288 * Reset it to default first.
1290 csp->config->default_permissions = PERMIT_RE_FILTER;
1292 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1296 permissions = PERMIT_COOKIE_SET | PERMIT_COOKIE_READ | PERMIT_POPUPS;
1299 * FIXME: for() loop is a kludge. Want to loop around until we
1300 * find a non-control character. Assume there will be at most 4
1303 for (i = 0; i < 4; i++)
1309 * Allow cookies to be read by the server, but do
1310 * not allow them to be set.
1312 permissions = (permissions & ~PERMIT_COOKIE_SET);
1318 * Allow server to set cookies but do not let the
1321 permissions = (permissions & ~PERMIT_COOKIE_READ);
1329 permissions = (permissions & ~PERMIT_POPUPS);
1335 * Permit filtering using PCRS
1337 permissions = (permissions | PERMIT_RE_FILTER);
1343 * All of the above (maximum filtering).
1345 permissions = PERMIT_RE_FILTER;
1351 * FIXME: Should break out of the loop here.
1358 * Elide any of the "special" chars from the
1359 * front of the pattern
1364 while ((*q++ = *p++) != '\0')
1370 /* a lines containing only "special" chars sets default */
1373 csp->config->default_permissions = permissions;
1377 /* allocate a new node */
1378 if (((b = zalloc(sizeof(*b))) == NULL)
1382 goto load_permissions_error;
1385 /* add it to the list */
1390 b->permissions = permissions;
1392 /* Save the URL pattern */
1393 if (create_url_spec(b->url, buf))
1396 goto load_permissions_error;
1402 #ifndef SPLIT_PROXY_ARGS
1403 if (!suppress_blocklists)
1405 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1407 #endif /* ndef SPLIT_PROXY_ARGS */
1409 /* the old one is now obsolete */
1410 if (current_permissions_file)
1412 current_permissions_file->unloader = unload_permissions_file;
1415 fs->next = files->next;
1417 current_permissions_file = fs;
1421 csp->permissions_list = fs;
1426 load_permissions_error:
1427 log_error(LOG_LEVEL_ERROR, "can't load permissions file '%s': %E",
1428 csp->config->permissions_file);
1435 /*********************************************************************
1437 * Function : load_trustfile
1439 * Description : Read and parse a trustfile and add to files list.
1442 * 1 : csp = Current client state (buffers, headers, etc...)
1444 * Returns : 0 => Ok, everything else is an error.
1446 *********************************************************************/
1447 int load_trustfile(struct client_state *csp)
1451 struct block_spec *b, *bl;
1452 struct url_spec **tl;
1454 char buf[BUFSIZ], *p, *q;
1455 int reject, trusted;
1456 struct file_list *fs;
1458 if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
1460 /* No need to load */
1463 csp->tlist = current_trustfile;
1469 goto load_trustfile_error;
1472 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1475 goto load_trustfile_error;
1478 if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
1480 goto load_trustfile_error;
1483 tl = csp->config->trust_list;
1485 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1501 while ((*p++ = *q++))
1507 /* skip blank lines */
1513 /* allocate a new node */
1514 if ((b = zalloc(sizeof(*b))) == NULL)
1517 goto load_trustfile_error;
1520 /* add it to the list */
1526 /* Save the URL pattern */
1527 if (create_url_spec(b->url, buf))
1530 goto load_trustfile_error;
1534 * save a pointer to URL's spec in the list of trusted URL's, too
1546 #ifndef SPLIT_PROXY_ARGS
1547 if (!suppress_blocklists)
1549 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1551 #endif /* ndef SPLIT_PROXY_ARGS */
1553 /* the old one is now obsolete */
1554 if (current_trustfile)
1556 current_trustfile->unloader = unload_trustfile;
1559 fs->next = files->next;
1561 current_trustfile = fs;
1570 load_trustfile_error:
1571 log_error(LOG_LEVEL_ERROR, "can't load trustfile '%s': %E",
1572 csp->config->trustfile);
1576 #endif /* def TRUST_FILES */
1579 /*********************************************************************
1581 * Function : load_forwardfile
1583 * Description : Read and parse a forwardfile and add to files list.
1586 * 1 : csp = Current client state (buffers, headers, etc...)
1588 * Returns : 0 => Ok, everything else is an error.
1590 *********************************************************************/
1591 int load_forwardfile(struct client_state *csp)
1595 struct forward_spec *b, *bl;
1596 char buf[BUFSIZ], *p, *q, *tmp;
1598 int port, n, reject;
1599 struct file_list *fs;
1600 const struct gateway *gw;
1601 struct url_spec url[1];
1603 if (!check_file_changed(current_forwardfile, csp->config->forwardfile, &fs))
1605 /* No need to load */
1608 csp->flist = current_forwardfile;
1614 goto load_forwardfile_error;
1617 fs->f = bl = (struct forward_spec *)zalloc(sizeof(*bl));
1619 if ((fs == NULL) || (bl == NULL))
1621 goto load_forwardfile_error;
1624 if ((fp = fopen(csp->config->forwardfile, "r")) == NULL)
1626 goto load_forwardfile_error;
1631 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1637 n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1641 log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1645 strcpy(buf, vec[0]);
1654 while ((*p++ = *q++))
1660 /* skip lines containing only ~ */
1666 /* allocate a new node */
1667 if (((b = zalloc(sizeof(*b))) == NULL)
1669 || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
1674 goto load_forwardfile_error;
1677 /* add it to the list */
1681 /* save a copy of the orignal specification */
1682 if ((b->url->spec = strdup(buf)) == NULL)
1685 goto load_forwardfile_error;
1690 if ((p = strchr(buf, '/')))
1692 b->url->path = strdup(p);
1693 b->url->pathlen = strlen(b->url->path);
1698 b->url->path = NULL;
1699 b->url->pathlen = 0;
1707 sprintf(rebuf, "^(%s)", b->url->path);
1709 errcode = regcomp(b->url->preg, rebuf,
1710 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
1714 size_t errlen = regerror(errcode, b->url->preg, buf, sizeof(buf));
1718 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
1721 goto load_forwardfile_error;
1726 freez(b->url->preg);
1729 if ((p = strchr(buf, ':')) == NULL)
1739 b->url->port = port;
1741 if ((b->url->domain = strdup(buf)) == NULL)
1744 goto load_forwardfile_error;
1747 /* split domain into components */
1748 *url = dsplit(b->url->domain);
1749 b->url->dbuf = url->dbuf;
1750 b->url->dcnt = url->dcnt;
1751 b->url->dvec = url->dvec;
1753 /* now parse the gateway specs */
1757 for (gw = gateways; gw->name; gw++)
1759 if (strcmp(gw->name, p) == 0)
1765 if (gw->name == NULL)
1767 goto load_forwardfile_error;
1770 /* save this as the gateway type */
1773 /* now parse the gateway host[:port] spec */
1776 if (strcmp(p, ".") != 0)
1778 b->gw->gateway_host = strdup(p);
1780 if ((p = strchr(b->gw->gateway_host, ':')))
1783 b->gw->gateway_port = atoi(p);
1786 if (b->gw->gateway_port <= 0)
1788 goto load_forwardfile_error;
1792 /* now parse the forwarding spec */
1795 if (strcmp(p, ".") != 0)
1797 b->gw->forward_host = strdup(p);
1799 if ((p = strchr(b->gw->forward_host, ':')))
1802 b->gw->forward_port = atoi(p);
1805 if (b->gw->forward_port <= 0)
1807 b->gw->forward_port = 8000;
1816 #ifndef SPLIT_PROXY_ARGS
1817 if (!suppress_blocklists)
1819 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1821 #endif /* ndef SPLIT_PROXY_ARGS */
1823 /* the old one is now obsolete */
1824 if (current_forwardfile)
1826 current_forwardfile->unloader = unload_forwardfile;
1829 fs->next = files->next;
1831 current_forwardfile = fs;
1840 load_forwardfile_error:
1841 log_error(LOG_LEVEL_ERROR, "can't load forwardfile '%s': %E",
1842 csp->config->forwardfile);
1849 /*********************************************************************
1851 * Function : load_re_filterfile
1853 * Description : Load the re_filterfile. Each non-comment, non-empty
1854 * line is instantly added to the joblist, which is
1855 * a chained list of pcrs_job structs.
1858 * 1 : csp = Current client state (buffers, headers, etc...)
1860 * Returns : 0 => Ok, everything else is an error.
1862 *********************************************************************/
1863 int load_re_filterfile(struct client_state *csp)
1867 struct re_filterfile_spec *bl;
1868 struct file_list *fs;
1874 if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1876 /* No need to load */
1879 csp->rlist = current_re_filterfile;
1885 goto load_re_filterfile_error;
1888 fs->f = bl = (struct re_filterfile_spec *)zalloc(sizeof(*bl));
1891 goto load_re_filterfile_error;
1894 /* Open the file or fail */
1895 if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1897 goto load_re_filterfile_error;
1900 /* Read line by line */
1901 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1903 enlist( bl->patterns, buf );
1905 /* We have a meaningful line -> make it a job */
1906 if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1908 log_error(LOG_LEVEL_RE_FILTER,
1909 "Adding re_filter job %s failed with error %d.", buf, error);
1914 dummy->next = bl->joblist;
1915 bl->joblist = dummy;
1916 log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1922 #ifndef SPLIT_PROXY_ARGS
1923 if (!suppress_blocklists)
1925 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1927 #endif /* ndef SPLIT_PROXY_ARGS */
1929 /* the old one is now obsolete */
1930 if ( NULL != current_re_filterfile )
1932 current_re_filterfile->unloader = unload_re_filterfile;
1935 fs->next = files->next;
1937 current_re_filterfile = fs;
1946 load_re_filterfile_error:
1947 log_error(LOG_LEVEL_ERROR, "can't load re_filterfile '%s': %E",
1948 csp->config->re_filterfile);
1952 #endif /* def PCRS */
1955 /*********************************************************************
1957 * Function : add_loader
1959 * Description : Called from `load_config'. Called once for each input
1960 * file found in config.
1963 * 1 : loader = pointer to a function that can parse and load
1964 * the appropriate config file.
1965 * 2 : config = The configuration_spec to add the loader to.
1969 *********************************************************************/
1970 void add_loader(int (*loader)(struct client_state *),
1971 struct configuration_spec * config)
1975 for (i=0; i < NLOADERS; i++)
1977 if (config->loaders[i] == NULL)
1979 config->loaders[i] = loader;
1987 /*********************************************************************
1989 * Function : run_loader
1991 * Description : Called from `load_config' and `listen_loop'. This
1992 * function keeps the "csp" current with any file mods
1993 * since the last loop. If a file is unchanged, the
1994 * loader functions do NOT reload the file.
1997 * 1 : csp = Current client state (buffers, headers, etc...)
1998 * Must be non-null. Reads: "csp->config"
1999 * Writes: various data members.
2001 * Returns : 0 => Ok, everything else is an error.
2003 *********************************************************************/
2004 int run_loader(struct client_state *csp)
2009 for (i=0; i < NLOADERS; i++)
2011 if (csp->config->loaders[i] == NULL)
2015 ret |= (csp->config->loaders[i])(csp);