1 const char loaders_rcs[] = "$Id: loaders.c,v 1.8 2001/05/26 00:55:20 jongfoster 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.8 2001/05/26 00:55:20 jongfoster
39 * Removing duplicated code. load_forwardfile() now uses create_url_spec()
41 * Revision 1.7 2001/05/26 00:28:36 jongfoster
42 * Automatic reloading of config file.
43 * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
44 * Most of the global variables have been moved to a new
45 * struct configuration_spec, accessed through csp->config->globalname
46 * Most of the globals remaining are used by the Win32 GUI.
48 * Revision 1.6 2001/05/23 12:27:33 oes
50 * Fixed ugly indentation of my last changes
52 * Revision 1.5 2001/05/23 10:39:05 oes
53 * - Added support for escaping the comment character
54 * in config files by a backslash
55 * - Added support for line continuation in config
57 * - Fixed a buffer overflow bug with long config lines
59 * Revision 1.4 2001/05/22 18:56:28 oes
62 * Revision 1.3 2001/05/20 01:21:20 jongfoster
63 * Version 2.9.4 checkin.
64 * - Merged popupfile and cookiefile, and added control over PCRS
65 * filtering, in new "permissionsfile".
66 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
67 * file error you now get a message box (in the Win32 GUI) rather
68 * than the program exiting with no explanation.
69 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
71 * - Removed tabs from "config"
72 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
73 * - Bumped up version number.
75 * Revision 1.2 2001/05/17 23:01:01 oes
76 * - Cleaned CRLF's from the sources and related files
78 * Revision 1.1.1.1 2001/05/15 13:58:59 oes
79 * Initial import of version 2.9.3 source tree
82 *********************************************************************/
89 #include <sys/types.h>
107 #include "miscutil.h"
111 #ifndef SPLIT_PROXY_ARGS
113 #include "showargs.h"
114 #endif /* ndef SPLIT_PROXY_ARGS */
116 const char loaders_h_rcs[] = LOADERS_H_VERSION;
118 /* Fix a problem with Solaris. There should be no effect on other
120 * Solaris's isspace() is a macro which uses it's argument directly
121 * as an array index. Therefore we need to make sure that high-bit
122 * characters generate +ve values, and ideally we also want to make
123 * the argument match the declared parameter type of "int".
125 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
129 * Currently active files.
130 * These are also entered in the main linked list of files.
132 static struct file_list *current_blockfile = NULL;
133 static struct file_list *current_permissions_file = NULL;
134 static struct file_list *current_forwardfile = NULL;
137 static struct file_list *current_aclfile = NULL;
138 #endif /* def ACL_FILES */
140 #ifdef USE_IMAGE_LIST
141 static struct file_list *current_imagefile = NULL;
142 #endif /* def USE_IMAGE_LIST */
145 static struct file_list *current_trustfile = NULL;
146 #endif /* def TRUST_FILES */
149 static struct file_list *current_re_filterfile = NULL;
150 #endif /* def PCRS */
153 static int create_url_spec(struct url_spec * url, char * buf);
156 /*********************************************************************
160 * Description : Basically a mark and sweep garbage collector, it is run
161 * (by the parent thread) every once in a while to reclaim memory.
163 * It uses a mark and sweep strategy:
164 * 1) mark all files as inactive
166 * 2) check with each client:
167 * if it is active, mark its files as active
168 * if it is inactive, free its resources
170 * 3) free the resources of all of the files that
171 * are still marked as inactive (and are obsolete).
173 * N.B. files that are not obsolete don't have an unloader defined.
179 *********************************************************************/
182 struct file_list *fl, *nfl;
183 struct client_state *csp, *ncsp;
185 /* clear all of the file's active flags */
186 for ( fl = files->next; NULL != fl; fl = fl->next )
191 for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
195 /* mark this client's files as active */
198 * Always have a configuration file.
199 * (Also note the slightly non-standard extra
202 ncsp->config->config_file_list->active = 1;
204 if (ncsp->blist) /* block files */
206 ncsp->blist->active = 1;
209 if (ncsp->permissions_list) /* permissions files */
211 ncsp->permissions_list->active = 1;
214 if (ncsp->flist) /* forward files */
216 ncsp->flist->active = 1;
220 if (ncsp->alist) /* acl files */
222 ncsp->alist->active = 1;
224 #endif /* def ACL_FILES */
226 #ifdef USE_IMAGE_LIST
227 if (ncsp->ilist) /* image files */
229 ncsp->ilist->active = 1;
231 #endif /* def USE_IMAGE_LIST */
234 if (ncsp->rlist) /* perl re files */
236 ncsp->rlist->active = 1;
238 #endif /* def PCRS */
241 if (ncsp->tlist) /* trust files */
243 ncsp->tlist->active = 1;
245 #endif /* def TRUST_FILES */
250 /* this client one is not active, release its resources */
251 csp->next = ncsp->next;
253 freez(ncsp->ip_addr_str);
254 freez(ncsp->referrer);
255 freez(ncsp->x_forwarded);
256 freez(ncsp->ip_addr_str);
257 freez(ncsp->iob->buf);
259 free_http_request(ncsp->http);
261 destroy_list(ncsp->headers);
262 destroy_list(ncsp->cookie_list);
270 #endif /* def STATISTICS */
276 for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
278 if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
280 fl->next = nfl->next;
282 (nfl->unloader)(nfl->f);
284 #ifndef SPLIT_PROXY_ARGS
285 freez(nfl->proxy_args);
286 #endif /* ndef SPLIT_PROXY_ARGS */
288 freez(nfl->filename);
297 /*********************************************************************
299 * Function : create_url_spec
301 * Description : Creates a "url_spec" structure from a string.
302 * When finished, free with unload_url().
305 * 1 : url = Target url_spec to be filled in. Must be
306 * zeroed out before the call (e.g. using zalloc).
307 * 2 : buf = Source pattern, null terminated. NOTE: The
308 * contents of this buffer are destroyed by this
309 * function. If this function succeeds, the
310 * buffer is copied to url->spec. If this
311 * function fails, the contents of the buffer
314 * Returns : 0 => Ok, everything else is an error.
316 *********************************************************************/
317 static int create_url_spec(struct url_spec * url, char * buf)
320 struct url_spec tmp_url[1];
322 /* paranoia - should never happen. */
323 if ((url == NULL) || (buf == NULL))
328 /* save a copy of the orignal specification */
329 if ((url->spec = strdup(buf)) == NULL)
334 if ((p = strchr(buf, '/')))
336 if (NULL == (url->path = strdup(p)))
341 url->pathlen = strlen(url->path);
355 if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
362 sprintf(rebuf, "^(%s)", url->path);
364 errcode = regcomp(url->preg, rebuf,
365 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
370 url->preg, buf, sizeof(buf));
374 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
385 if ((p = strchr(buf, ':')) == NULL)
395 if ((url->domain = strdup(buf)) == NULL)
401 #endif /* def REGEX */
405 /* split domain into components */
407 *tmp_url = dsplit(url->domain);
408 url->dbuf = tmp_url->dbuf;
409 url->dcnt = tmp_url->dcnt;
410 url->dvec = tmp_url->dvec;
416 /*********************************************************************
418 * Function : unload_url
420 * Description : Called from the "unloaders". Freez the url
421 * structure elements.
424 * 1 : url = pointer to a url_spec structure.
428 *********************************************************************/
429 static void unload_url(struct url_spec *url)
431 if (url == NULL) return;
450 /*********************************************************************
452 * Function : unload_aclfile
454 * Description : Unloads an aclfile.
457 * 1 : f = the data structure associated with the aclfile.
461 *********************************************************************/
462 static void unload_aclfile(void *f)
464 struct access_control_list *b = (struct access_control_list *)f;
465 if (b == NULL) return;
467 unload_aclfile(b->next);
472 #endif /* def ACL_FILES */
474 /*********************************************************************
476 * Function : unload_blockfile
478 * Description : Unloads a blockfile.
481 * 1 : f = the data structure associated with the blockfile.
485 *********************************************************************/
486 static void unload_blockfile(void *f)
488 struct block_spec *b = (struct block_spec *)f;
489 if (b == NULL) return;
491 unload_blockfile(b->next);
500 #ifdef USE_IMAGE_LIST
501 /*********************************************************************
503 * Function : unload_imagefile
505 * Description : Unloads an imagefile.
508 * 1 : f = the data structure associated with the imagefile.
512 *********************************************************************/
513 static void unload_imagefile(void *f)
515 struct block_spec *b = (struct block_spec *)f;
516 if (b == NULL) return;
518 unload_imagefile(b->next);
525 #endif /* def USE_IMAGE_LIST */
528 /*********************************************************************
530 * Function : unload_permissions_file
532 * Description : Unloads a permissions file.
535 * 1 : file_data = the data structure associated with the
540 *********************************************************************/
541 static void unload_permissions_file(void *file_data)
543 struct permissions_spec * next;
544 struct permissions_spec * cur = (struct permissions_spec *)file_data;
548 unload_url(cur->url);
557 /*********************************************************************
559 * Function : unload_trustfile
561 * Description : Unloads a trustfile.
564 * 1 : f = the data structure associated with the trustfile.
568 *********************************************************************/
569 static void unload_trustfile(void *f)
571 struct block_spec *b = (struct block_spec *)f;
572 if (b == NULL) return;
574 unload_trustfile(b->next);
581 #endif /* def TRUST_FILES */
584 /*********************************************************************
586 * Function : unload_forwardfile
588 * Description : Unloads a forwardfile.
591 * 1 : f = the data structure associated with the forwardfile.
595 *********************************************************************/
596 static void unload_forwardfile(void *f)
598 struct forward_spec *b = (struct forward_spec *)f;
599 if (b == NULL) return;
601 unload_forwardfile(b->next);
605 freez(b->gw->gateway_host);
606 freez(b->gw->forward_host);
614 /*********************************************************************
616 * Function : unload_re_filterfile
618 * Description : Unload the re_filter list.
621 * 1 : f = the data structure associated with the filterfile.
625 *********************************************************************/
626 static void unload_re_filterfile(void *f)
629 struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
631 if (b == NULL) return;
633 destroy_list(b->patterns);
635 joblist = b->joblist;
636 while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
641 #endif /* def PCRS */
644 /*********************************************************************
646 * Function : check_file_changed
648 * Description : Helper function to check if a file needs reloading.
649 * If "current" is still current, return it. Otherwise
650 * allocates a new (zeroed) "struct file_list", fills
651 * in the disk file name and timestamp, and returns it.
654 * 1 : current = The file_list currently being used - will
655 * be checked to see if it is out of date.
656 * May be NULL (which is treated as out of
658 * 2 : filename = Name of file to check.
659 * 3 : newfl = New file list. [Output only]
660 * This will be set to NULL, OR a struct
661 * file_list newly allocated on the
662 * heap, with the filename and lastmodified
663 * fields filled, standard header giving file
664 * name in proxy_args, and all others zeroed.
665 * (proxy_args is only filled in if !defined
666 * SPLIT_PROXY_ARGS and !suppress_blocklists).
668 * Returns : If file unchanged: 0 (and sets newfl == NULL)
669 * If file changed: 1 and sets newfl != NULL
670 * On error: 1 and sets newfl == NULL
672 *********************************************************************/
673 int check_file_changed(const struct file_list * current,
674 const char * filename,
675 struct file_list ** newfl)
677 struct file_list *fs;
678 struct stat statbuf[1];
682 if (stat(filename, statbuf) < 0)
684 /* Error, probably file not found. */
689 && (current->lastmodified == statbuf->st_mtime)
690 && (0 == strcmp(current->filename, filename)))
695 fs = (struct file_list *)zalloc(sizeof(struct file_list));
699 /* Out of memory error */
703 fs->filename = strdup(filename);
704 fs->lastmodified = statbuf->st_mtime;
706 if (fs->filename == NULL)
708 /* Out of memory error */
713 #ifndef SPLIT_PROXY_ARGS
714 if (!suppress_blocklists)
716 char * p = html_encode(filename);
719 fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
720 fs->proxy_args = strsav(fs->proxy_args, p);
721 fs->proxy_args = strsav(fs->proxy_args,
722 "' contains the following patterns</h2>\n");
725 fs->proxy_args = strsav(fs->proxy_args, "<pre>");
727 #endif /* ndef SPLIT_PROXY_ARGS */
734 /*********************************************************************
736 * Function : read_config_line
738 * Description : Read a single non-empty line from a file and return
739 * it. Trims comments, leading and trailing whitespace
740 * and respects escaping of newline and comment char.
741 * Also writes the file to fs->proxy_args.
744 * 1 : buf = Buffer to use.
745 * 2 : buflen = Size of buffer in bytes.
746 * 3 : fp = File to read from
747 * 4 : fs = File will be written to fs->proxy_args. May
748 * be NULL to disable this feature.
750 * Returns : NULL on EOF or error
751 * Otherwise, returns buf.
753 *********************************************************************/
754 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
757 char linebuf[BUFSIZ];
762 while (fgets(linebuf, sizeof(linebuf), fp))
764 #ifndef SPLIT_PROXY_ARGS
765 if (fs && !suppress_blocklists)
767 char *html_line = html_encode(linebuf);
768 if (html_line != NULL)
770 fs->proxy_args = strsav(fs->proxy_args, html_line);
773 fs->proxy_args = strsav(fs->proxy_args, "<br>");
775 #endif /* ndef SPLIT_PROXY_ARGS */
777 /* Trim off newline */
778 if ((p = strpbrk(linebuf, "\r\n")) != NULL)
783 /* Line continuation? Trim escape and set flag. */
784 if ((p != linebuf) && (*--p == '\\'))
790 /* If there's a comment char.. */
791 if ((p = strpbrk(linebuf, "#")) != NULL)
793 /* ..and it's escaped, left-shift the line over the escape. */
794 if ((p != linebuf) && (*(p-1) == '\\'))
797 while ((*q++ = *p++) != '\0') /* nop */;
799 /* Else, chop off the rest of the line */
806 /* Trim leading whitespace */
808 while (*p && ijb_isspace(*p))
815 /* There is something other than whitespace on the line. */
817 /* Move the data to the start of buf */
820 /* strcpy that can cope with overlap. */
822 while ((*q++ = *p++) != '\0')
828 /* Trim trailing whitespace */
829 p = linebuf + strlen(linebuf) - 1;
832 * Note: the (p >= linebuf) below is paranoia, it's not really needed.
833 * When p == linebuf then ijb_isspace(*p) will be false and we'll drop
836 while ((p >= linebuf) && ijb_isspace(*p))
842 /* More paranoia. This if statement is always true. */
845 strncat(buf, linebuf, buflen - strlen(buf));
865 /*********************************************************************
867 * Function : load_aclfile
869 * Description : Read and parse an aclfile and add to files list.
872 * 1 : csp = Current client state (buffers, headers, etc...)
874 * Returns : 0 => Ok, everything else is an error.
876 *********************************************************************/
877 int load_aclfile(struct client_state *csp)
880 char buf[BUFSIZ], *v[3], *p;
882 struct access_control_list *a, *bl;
883 struct file_list *fs;
885 if (!check_file_changed(current_aclfile, csp->config->aclfile, &fs))
887 /* No need to load */
890 csp->alist = current_aclfile;
896 goto load_aclfile_error;
899 fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
904 goto load_aclfile_error;
907 fp = fopen(csp->config->aclfile, "r");
911 goto load_aclfile_error;
914 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
916 i = ssplit(buf, " \t", v, SZ(v), 1, 1);
918 /* allocate a new node */
919 a = (struct access_control_list *) zalloc(sizeof(*a));
927 goto load_aclfile_error;
930 /* add it to the list */
937 if (acl_addr(v[2], a->dst) < 0)
939 goto load_aclfile_error;
944 if (acl_addr(v[1], a->src) < 0)
946 goto load_aclfile_error;
950 if (strcmpic(p, "permit") == 0)
952 a->action = ACL_PERMIT;
956 if (strcmpic(p, "deny") == 0)
958 a->action = ACL_DENY;
964 goto load_aclfile_error;
970 #ifndef SPLIT_PROXY_ARGS
971 if (!suppress_blocklists)
973 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
975 #endif /* ndef SPLIT_PROXY_ARGS */
979 current_aclfile->unloader = unload_aclfile;
982 fs->next = files->next;
984 current_aclfile = fs;
994 log_error(LOG_LEVEL_FATAL, "can't load access control list %s: %E",
995 csp->config->aclfile);
999 #endif /* def ACL_FILES */
1002 /*********************************************************************
1004 * Function : load_blockfile
1006 * Description : Read and parse a blockfile and add to files list.
1009 * 1 : csp = Current client state (buffers, headers, etc...)
1011 * Returns : 0 => Ok, everything else is an error.
1013 *********************************************************************/
1014 int load_blockfile(struct client_state *csp)
1018 struct block_spec *b, *bl;
1019 char buf[BUFSIZ], *p, *q;
1021 struct file_list *fs;
1023 if (!check_file_changed(current_blockfile, csp->config->blockfile, &fs))
1025 /* No need to load */
1028 csp->blist = current_blockfile;
1034 goto load_blockfile_error;
1037 fs->f = bl = (struct block_spec *) zalloc(sizeof(*bl));
1040 goto load_blockfile_error;
1043 if ((fp = fopen(csp->config->blockfile, "r")) == NULL)
1045 goto load_blockfile_error;
1048 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1057 while ((*p++ = *q++))
1063 /* skip lines containing only ~ */
1069 /* allocate a new node */
1070 if ((b = zalloc(sizeof(*b))) == NULL)
1073 goto load_blockfile_error;
1076 /* add it to the list */
1082 /* Save the URL pattern */
1083 if (create_url_spec(b->url, buf))
1086 goto load_blockfile_error;
1092 #ifndef SPLIT_PROXY_ARGS
1093 if (!suppress_blocklists)
1095 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1097 #endif /* ndef SPLIT_PROXY_ARGS */
1099 /* the old one is now obsolete */
1100 if (current_blockfile)
1102 current_blockfile->unloader = unload_blockfile;
1105 fs->next = files->next;
1107 current_blockfile = fs;
1116 load_blockfile_error:
1117 log_error(LOG_LEVEL_FATAL, "can't load blockfile '%s': %E", csp->config->blockfile);
1123 #ifdef USE_IMAGE_LIST
1124 /*********************************************************************
1126 * Function : load_imagefile
1128 * Description : Read and parse an imagefile and add to files list.
1131 * 1 : csp = Current client state (buffers, headers, etc...)
1133 * Returns : 0 => Ok, everything else is an error.
1135 *********************************************************************/
1136 int load_imagefile(struct client_state *csp)
1140 struct block_spec *b, *bl;
1141 char buf[BUFSIZ], *p, *q;
1143 struct file_list *fs;
1145 if (!check_file_changed(current_imagefile, csp->config->imagefile, &fs))
1147 /* No need to load */
1150 csp->ilist = current_imagefile;
1156 goto load_imagefile_error;
1159 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1162 goto load_imagefile_error;
1165 if ((fp = fopen(csp->config->imagefile, "r")) == NULL)
1167 goto load_imagefile_error;
1170 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1179 while ((*p++ = *q++))
1185 /* skip lines containing only ~ */
1191 /* allocate a new node */
1192 if ((b = zalloc(sizeof(*b))) == NULL)
1195 goto load_imagefile_error;
1198 /* add it to the list */
1204 /* Save the URL pattern */
1205 if (create_url_spec(b->url, buf))
1208 goto load_imagefile_error;
1214 #ifndef SPLIT_PROXY_ARGS
1215 if (!suppress_blocklists)
1217 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1219 #endif /* ndef SPLIT_PROXY_ARGS */
1221 /* the old one is now obsolete */
1222 if (current_imagefile)
1224 current_imagefile->unloader = unload_imagefile;
1227 fs->next = files->next;
1229 current_imagefile = fs;
1238 load_imagefile_error:
1239 log_error(LOG_LEVEL_FATAL, "can't load imagefile '%s': %E", csp->config->imagefile);
1243 #endif /* def USE_IMAGE_LIST */
1246 /*********************************************************************
1248 * Function : load_permissions_file
1250 * Description : Read and parse a permissions file and add to files
1254 * 1 : csp = Current client state (buffers, headers, etc...)
1256 * Returns : 0 => Ok, everything else is an error.
1258 *********************************************************************/
1259 int load_permissions_file(struct client_state *csp)
1263 struct permissions_spec *b, *bl;
1264 char buf[BUFSIZ], *p, *q;
1266 struct file_list *fs;
1269 if (!check_file_changed(current_permissions_file, csp->config->permissions_file, &fs))
1271 /* No need to load */
1274 csp->permissions_list = current_permissions_file;
1280 goto load_permissions_error;
1283 fs->f = bl = (struct permissions_spec *)zalloc(sizeof(*bl));
1286 goto load_permissions_error;
1289 if ((fp = fopen(csp->config->permissions_file, "r")) == NULL)
1291 goto load_permissions_error;
1296 * default_permissions is set in this file.
1298 * Reset it to default first.
1300 csp->config->default_permissions = PERMIT_RE_FILTER;
1302 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1306 permissions = PERMIT_COOKIE_SET | PERMIT_COOKIE_READ | PERMIT_POPUPS;
1309 * FIXME: for() loop is a kludge. Want to loop around until we
1310 * find a non-control character. Assume there will be at most 4
1313 for (i = 0; i < 4; i++)
1319 * Allow cookies to be read by the server, but do
1320 * not allow them to be set.
1322 permissions = (permissions & ~PERMIT_COOKIE_SET);
1328 * Allow server to set cookies but do not let the
1331 permissions = (permissions & ~PERMIT_COOKIE_READ);
1339 permissions = (permissions & ~PERMIT_POPUPS);
1345 * Permit filtering using PCRS
1347 permissions = (permissions | PERMIT_RE_FILTER);
1353 * All of the above (maximum filtering).
1355 permissions = PERMIT_RE_FILTER;
1361 * FIXME: Should break out of the loop here.
1368 * Elide any of the "special" chars from the
1369 * front of the pattern
1374 while ((*q++ = *p++) != '\0')
1380 /* a lines containing only "special" chars sets default */
1383 csp->config->default_permissions = permissions;
1387 /* allocate a new node */
1388 if (((b = zalloc(sizeof(*b))) == NULL)
1392 goto load_permissions_error;
1395 /* add it to the list */
1400 b->permissions = permissions;
1402 /* Save the URL pattern */
1403 if (create_url_spec(b->url, buf))
1406 goto load_permissions_error;
1412 #ifndef SPLIT_PROXY_ARGS
1413 if (!suppress_blocklists)
1415 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1417 #endif /* ndef SPLIT_PROXY_ARGS */
1419 /* the old one is now obsolete */
1420 if (current_permissions_file)
1422 current_permissions_file->unloader = unload_permissions_file;
1425 fs->next = files->next;
1427 current_permissions_file = fs;
1431 csp->permissions_list = fs;
1436 load_permissions_error:
1437 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': %E",
1438 csp->config->permissions_file);
1445 /*********************************************************************
1447 * Function : load_trustfile
1449 * Description : Read and parse a trustfile and add to files list.
1452 * 1 : csp = Current client state (buffers, headers, etc...)
1454 * Returns : 0 => Ok, everything else is an error.
1456 *********************************************************************/
1457 int load_trustfile(struct client_state *csp)
1461 struct block_spec *b, *bl;
1462 struct url_spec **tl;
1464 char buf[BUFSIZ], *p, *q;
1465 int reject, trusted;
1466 struct file_list *fs;
1468 if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
1470 /* No need to load */
1473 csp->tlist = current_trustfile;
1479 goto load_trustfile_error;
1482 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1485 goto load_trustfile_error;
1488 if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
1490 goto load_trustfile_error;
1493 tl = csp->config->trust_list;
1495 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1511 while ((*p++ = *q++))
1517 /* skip blank lines */
1523 /* allocate a new node */
1524 if ((b = zalloc(sizeof(*b))) == NULL)
1527 goto load_trustfile_error;
1530 /* add it to the list */
1536 /* Save the URL pattern */
1537 if (create_url_spec(b->url, buf))
1540 goto load_trustfile_error;
1544 * save a pointer to URL's spec in the list of trusted URL's, too
1556 #ifndef SPLIT_PROXY_ARGS
1557 if (!suppress_blocklists)
1559 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1561 #endif /* ndef SPLIT_PROXY_ARGS */
1563 /* the old one is now obsolete */
1564 if (current_trustfile)
1566 current_trustfile->unloader = unload_trustfile;
1569 fs->next = files->next;
1571 current_trustfile = fs;
1580 load_trustfile_error:
1581 log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1582 csp->config->trustfile);
1586 #endif /* def TRUST_FILES */
1589 /*********************************************************************
1591 * Function : load_forwardfile
1593 * Description : Read and parse a forwardfile and add to files list.
1596 * 1 : csp = Current client state (buffers, headers, etc...)
1598 * Returns : 0 => Ok, everything else is an error.
1600 *********************************************************************/
1601 int load_forwardfile(struct client_state *csp)
1605 struct forward_spec *b, *bl;
1606 char buf[BUFSIZ], *p, *q, *tmp;
1609 struct file_list *fs;
1610 const struct gateway *gw;
1612 if (!check_file_changed(current_forwardfile, csp->config->forwardfile, &fs))
1614 /* No need to load */
1617 csp->flist = current_forwardfile;
1623 goto load_forwardfile_error;
1626 fs->f = bl = (struct forward_spec *)zalloc(sizeof(*bl));
1628 if ((fs == NULL) || (bl == NULL))
1630 goto load_forwardfile_error;
1633 if ((fp = fopen(csp->config->forwardfile, "r")) == NULL)
1635 goto load_forwardfile_error;
1640 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1646 n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1650 log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1654 strcpy(buf, vec[0]);
1663 while ((*p++ = *q++))
1669 /* skip lines containing only ~ */
1675 /* allocate a new node */
1676 if (((b = zalloc(sizeof(*b))) == NULL)
1680 goto load_forwardfile_error;
1683 /* add it to the list */
1687 b->reject = reject;
\r
1689 /* Save the URL pattern */
\r
1690 if (create_url_spec(b->url, buf))
\r
1693 goto load_forwardfile_error;
\r
1696 /* now parse the gateway specs */
1700 for (gw = gateways; gw->name; gw++)
1702 if (strcmp(gw->name, p) == 0)
1708 if (gw->name == NULL)
1710 goto load_forwardfile_error;
1713 /* save this as the gateway type */
1716 /* now parse the gateway host[:port] spec */
1719 if (strcmp(p, ".") != 0)
1721 b->gw->gateway_host = strdup(p);
1723 if ((p = strchr(b->gw->gateway_host, ':')))
1726 b->gw->gateway_port = atoi(p);
1729 if (b->gw->gateway_port <= 0)
1731 goto load_forwardfile_error;
1735 /* now parse the forwarding spec */
1738 if (strcmp(p, ".") != 0)
1740 b->gw->forward_host = strdup(p);
1742 if ((p = strchr(b->gw->forward_host, ':')))
1745 b->gw->forward_port = atoi(p);
1748 if (b->gw->forward_port <= 0)
1750 b->gw->forward_port = 8000;
1759 #ifndef SPLIT_PROXY_ARGS
1760 if (!suppress_blocklists)
1762 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1764 #endif /* ndef SPLIT_PROXY_ARGS */
1766 /* the old one is now obsolete */
1767 if (current_forwardfile)
1769 current_forwardfile->unloader = unload_forwardfile;
1772 fs->next = files->next;
1774 current_forwardfile = fs;
1783 load_forwardfile_error:
1784 log_error(LOG_LEVEL_FATAL, "can't load forwardfile '%s': %E",
1785 csp->config->forwardfile);
1792 /*********************************************************************
1794 * Function : load_re_filterfile
1796 * Description : Load the re_filterfile. Each non-comment, non-empty
1797 * line is instantly added to the joblist, which is
1798 * a chained list of pcrs_job structs.
1801 * 1 : csp = Current client state (buffers, headers, etc...)
1803 * Returns : 0 => Ok, everything else is an error.
1805 *********************************************************************/
1806 int load_re_filterfile(struct client_state *csp)
1810 struct re_filterfile_spec *bl;
1811 struct file_list *fs;
1817 if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1819 /* No need to load */
1822 csp->rlist = current_re_filterfile;
1828 goto load_re_filterfile_error;
1831 fs->f = bl = (struct re_filterfile_spec *)zalloc(sizeof(*bl));
1834 goto load_re_filterfile_error;
1837 /* Open the file or fail */
1838 if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1840 goto load_re_filterfile_error;
1843 /* Read line by line */
1844 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1846 enlist( bl->patterns, buf );
1848 /* We have a meaningful line -> make it a job */
1849 if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1851 log_error(LOG_LEVEL_RE_FILTER,
1852 "Adding re_filter job %s failed with error %d.", buf, error);
1857 dummy->next = bl->joblist;
1858 bl->joblist = dummy;
1859 log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1865 #ifndef SPLIT_PROXY_ARGS
1866 if (!suppress_blocklists)
1868 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1870 #endif /* ndef SPLIT_PROXY_ARGS */
1872 /* the old one is now obsolete */
1873 if ( NULL != current_re_filterfile )
1875 current_re_filterfile->unloader = unload_re_filterfile;
1878 fs->next = files->next;
1880 current_re_filterfile = fs;
1889 load_re_filterfile_error:
1890 log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1891 csp->config->re_filterfile);
1895 #endif /* def PCRS */
1898 /*********************************************************************
1900 * Function : add_loader
1902 * Description : Called from `load_config'. Called once for each input
1903 * file found in config.
1906 * 1 : loader = pointer to a function that can parse and load
1907 * the appropriate config file.
1908 * 2 : config = The configuration_spec to add the loader to.
1912 *********************************************************************/
1913 void add_loader(int (*loader)(struct client_state *),
1914 struct configuration_spec * config)
1918 for (i=0; i < NLOADERS; i++)
1920 if (config->loaders[i] == NULL)
1922 config->loaders[i] = loader;
1930 /*********************************************************************
1932 * Function : run_loader
1934 * Description : Called from `load_config' and `listen_loop'. This
1935 * function keeps the "csp" current with any file mods
1936 * since the last loop. If a file is unchanged, the
1937 * loader functions do NOT reload the file.
1940 * 1 : csp = Current client state (buffers, headers, etc...)
1941 * Must be non-null. Reads: "csp->config"
1942 * Writes: various data members.
1944 * Returns : 0 => Ok, everything else is an error.
1946 *********************************************************************/
1947 int run_loader(struct client_state *csp)
1952 for (i=0; i < NLOADERS; i++)
1954 if (csp->config->loaders[i] == NULL)
1958 ret |= (csp->config->loaders[i])(csp);