1 const char loaders_rcs[] = "$Id: loaders.c,v 1.3 2001/05/20 01:21: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.3 2001/05/20 01:21:20 jongfoster
39 * Version 2.9.4 checkin.
40 * - Merged popupfile and cookiefile, and added control over PCRS
41 * filtering, in new "permissionsfile".
42 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
43 * file error you now get a message box (in the Win32 GUI) rather
44 * than the program exiting with no explanation.
45 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
47 * - Removed tabs from "config"
48 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
49 * - Bumped up version number.
51 * Revision 1.2 2001/05/17 23:01:01 oes
52 * - Cleaned CRLF's from the sources and related files
54 * Revision 1.1.1.1 2001/05/15 13:58:59 oes
55 * Initial import of version 2.9.3 source tree
58 *********************************************************************/
65 #include <sys/types.h>
87 #ifndef SPLIT_PROXY_ARGS
90 #endif /* ndef SPLIT_PROXY_ARGS */
92 const char loaders_h_rcs[] = LOADERS_H_VERSION;
94 /* Fix a problem with Solaris. There should be no effect on other
96 * Solaris's isspace() is a macro which uses it's argument directly
97 * as an array index. Therefore we need to make sure that high-bit
98 * characters generate +ve values, and ideally we also want to make
99 * the argument match the declared parameter type of "int".
101 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
105 static int (*loaders[NLOADERS])(struct client_state *);
109 * Currently active files.
110 * These are also entered in the main linked list of files.
112 static struct file_list *current_blockfile = NULL;
113 static struct file_list *current_permissions_file = NULL;
114 static struct file_list *current_forwardfile = NULL;
117 static struct file_list *current_aclfile = NULL;
118 #endif /* def ACL_FILES */
120 #ifdef USE_IMAGE_LIST
121 static struct file_list *current_imagefile = NULL;
122 #endif /* def USE_IMAGE_LIST */
125 static struct file_list *current_trustfile = NULL;
126 #endif /* def TRUST_FILES */
129 static struct file_list *current_re_filterfile = NULL;
130 #endif /* def PCRS */
133 static int create_url_spec(struct url_spec * url, char * buf);
136 /*********************************************************************
140 * Description : Basically a mark and sweep garbage collector, it is run
141 * (by the parent thread) every once in a while to reclaim memory.
143 * It uses a mark and sweep strategy:
144 * 1) mark all files as inactive
146 * 2) check with each client:
147 * if it is active, mark its files as active
148 * if it is inactive, free its resources
150 * 3) free the resources of all of the files that
151 * are still marked as inactive (and are obsolete).
153 * N.B. files that are not obsolete don't have an unloader defined.
159 *********************************************************************/
162 struct file_list *fl, *nfl;
163 struct client_state *csp, *ncsp;
165 /* clear all of the file's active flags */
166 for ( fl = files->next; NULL != fl; fl = fl->next )
171 for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
175 /* mark this client's files as active */
177 if (ncsp->blist) /* block files */
179 ncsp->blist->active = 1;
182 if (ncsp->permissions_list) /* permissions files */
184 ncsp->permissions_list->active = 1;
187 if (ncsp->flist) /* forward files */
189 ncsp->flist->active = 1;
193 if (ncsp->alist) /* acl files */
195 ncsp->alist->active = 1;
197 #endif /* def ACL_FILES */
199 #ifdef USE_IMAGE_LIST
200 if (ncsp->ilist) /* image files */
202 ncsp->ilist->active = 1;
204 #endif /* def USE_IMAGE_LIST */
207 if (ncsp->rlist) /* perl re files */
209 ncsp->rlist->active = 1;
211 #endif /* def PCRS */
214 if (ncsp->tlist) /* trust files */
216 ncsp->tlist->active = 1;
218 #endif /* def TRUST_FILES */
223 /* this client one is not active, release its resources */
224 csp->next = ncsp->next;
226 freez(ncsp->ip_addr_str);
227 freez(ncsp->referrer);
228 freez(ncsp->x_forwarded);
229 freez(ncsp->ip_addr_str);
230 freez(ncsp->iob->buf);
232 free_http_request(ncsp->http);
234 destroy_list(ncsp->headers);
235 destroy_list(ncsp->cookie_list);
243 #endif /* def STATISTICS */
249 for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
251 if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
253 fl->next = nfl->next;
255 (nfl->unloader)(nfl->f);
257 #ifndef SPLIT_PROXY_ARGS
258 freez(nfl->proxy_args);
259 #endif /* ndef SPLIT_PROXY_ARGS */
261 freez(nfl->filename);
270 /*********************************************************************
272 * Function : create_url_spec
274 * Description : Creates a "url_spec" structure from a string.
275 * When finished, free with unload_url().
278 * 1 : url = Target url_spec to be filled in. Must be
279 * zeroed out before the call (e.g. using zalloc).
280 * 2 : buf = Source pattern, null terminated. NOTE: The
281 * contents of this buffer are destroyed by this
282 * function. If this function succeeds, the
283 * buffer is copied to url->spec. If this
284 * function fails, the contents of the buffer
287 * Returns : 0 => Ok, everything else is an error.
289 *********************************************************************/
290 static int create_url_spec(struct url_spec * url, char * buf)
293 struct url_spec tmp_url[1];
295 /* paranoia - should never happen. */
296 if ((url == NULL) || (buf == NULL))
301 /* save a copy of the orignal specification */
302 if ((url->spec = strdup(buf)) == NULL)
307 if ((p = strchr(buf, '/')))
309 if (NULL == (url->path = strdup(p)))
314 url->pathlen = strlen(url->path);
328 if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
335 sprintf(rebuf, "^(%s)", url->path);
337 errcode = regcomp(url->preg, rebuf,
338 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
343 url->preg, buf, sizeof(buf));
347 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
358 if ((p = strchr(buf, ':')) == NULL)
368 if ((url->domain = strdup(buf)) == NULL)
374 #endif /* def REGEX */
378 /* split domain into components */
380 *tmp_url = dsplit(url->domain);
381 url->dbuf = tmp_url->dbuf;
382 url->dcnt = tmp_url->dcnt;
383 url->dvec = tmp_url->dvec;
389 /*********************************************************************
391 * Function : unload_url
393 * Description : Called from the "unloaders". Freez the url
394 * structure elements.
397 * 1 : url = pointer to a url_spec structure.
401 *********************************************************************/
402 static void unload_url(struct url_spec *url)
404 if (url == NULL) return;
423 /*********************************************************************
425 * Function : unload_aclfile
427 * Description : Unloads an aclfile.
430 * 1 : f = the data structure associated with the aclfile.
434 *********************************************************************/
435 static void unload_aclfile(void *f)
437 struct access_control_list *b = (struct access_control_list *)f;
438 if (b == NULL) return;
440 unload_aclfile(b->next);
445 #endif /* def ACL_FILES */
447 /*********************************************************************
449 * Function : unload_blockfile
451 * Description : Unloads a blockfile.
454 * 1 : f = the data structure associated with the blockfile.
458 *********************************************************************/
459 static void unload_blockfile(void *f)
461 struct block_spec *b = (struct block_spec *)f;
462 if (b == NULL) return;
464 unload_blockfile(b->next);
473 #ifdef USE_IMAGE_LIST
474 /*********************************************************************
476 * Function : unload_imagefile
478 * Description : Unloads an imagefile.
481 * 1 : f = the data structure associated with the imagefile.
485 *********************************************************************/
486 static void unload_imagefile(void *f)
488 struct block_spec *b = (struct block_spec *)f;
489 if (b == NULL) return;
491 unload_imagefile(b->next);
498 #endif /* def USE_IMAGE_LIST */
501 /*********************************************************************
503 * Function : unload_permissions_file
505 * Description : Unloads a permissions file.
508 * 1 : file_data = the data structure associated with the
513 *********************************************************************/
514 static void unload_permissions_file(void *file_data)
516 struct permissions_spec * next;
517 struct permissions_spec * cur = (struct permissions_spec *)file_data;
521 unload_url(cur->url);
530 /*********************************************************************
532 * Function : unload_trustfile
534 * Description : Unloads a trustfile.
537 * 1 : f = the data structure associated with the trustfile.
541 *********************************************************************/
542 static void unload_trustfile(void *f)
544 struct block_spec *b = (struct block_spec *)f;
545 if (b == NULL) return;
547 unload_trustfile(b->next);
554 #endif /* def TRUST_FILES */
557 /*********************************************************************
559 * Function : unload_forwardfile
561 * Description : Unloads a forwardfile.
564 * 1 : f = the data structure associated with the forwardfile.
568 *********************************************************************/
569 static void unload_forwardfile(void *f)
571 struct forward_spec *b = (struct forward_spec *)f;
572 if (b == NULL) return;
574 unload_forwardfile(b->next);
578 freez(b->gw->gateway_host);
579 freez(b->gw->forward_host);
587 /*********************************************************************
589 * Function : unload_re_filterfile
591 * Description : Unload the re_filter list.
594 * 1 : f = the data structure associated with the filterfile.
598 *********************************************************************/
599 static void unload_re_filterfile(void *f)
602 struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
604 if (b == NULL) return;
606 destroy_list(b->patterns);
608 joblist = b->joblist;
609 while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
614 #endif /* def PCRS */
617 /*********************************************************************
619 * Function : check_file_changed
621 * Description : Helper function to check if a file needs reloading.
622 * If "current" is still current, return it. Otherwise
623 * allocates a new (zeroed) "struct file_list", fills
624 * in the disk file name and timestamp, and returns it.
627 * 1 : current = The file_list currently being used - will
628 * be checked to see if it is out of date.
629 * May be NULL (which is treated as out of
631 * 2 : filename = Name of file to check.
632 * 3 : newfl = New file list. [Output only]
633 * This will be set to NULL, OR a struct
634 * file_list newly allocated on the
635 * heap, with the filename and lastmodified
636 * fields filled, standard header giving file
637 * name in proxy_args, and all others zeroed.
638 * (proxy_args is only filled in if !defined
639 * SPLIT_PROXY_ARGS and !suppress_blocklists).
641 * Returns : If file unchanged: 0 (and sets newfl == NULL)
642 * If file changed: 1 and sets newfl != NULL
643 * On error: 1 and sets newfl == NULL
645 *********************************************************************/
646 static int check_file_changed(const struct file_list * current,
647 const char * filename,
648 struct file_list ** newfl)
650 struct file_list *fs;
651 struct stat statbuf[1];
655 if (stat(filename, statbuf) < 0)
657 /* Error, probably file not found. */
662 && (current->lastmodified == statbuf->st_mtime)
663 && (0 == strcmp(current->filename, filename)))
668 fs = (struct file_list *)zalloc(sizeof(struct file_list));
672 /* Out of memory error */
676 fs->filename = strdup(filename);
677 fs->lastmodified = statbuf->st_mtime;
679 if (fs->filename == NULL)
681 /* Out of memory error */
686 #ifndef SPLIT_PROXY_ARGS
687 if (!suppress_blocklists)
689 char * p = html_encode(filename);
692 fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
693 fs->proxy_args = strsav(fs->proxy_args, p);
694 fs->proxy_args = strsav(fs->proxy_args,
695 "' contains the following patterns</h2>\n");
698 fs->proxy_args = strsav(fs->proxy_args, "<pre>");
700 #endif /* ndef SPLIT_PROXY_ARGS */
707 /*********************************************************************
709 * Function : read_config_line
711 * Description : Read a single non-empty line from a file and return
712 * it. Trims comments, leading and trailing whitespace.
713 * Also wites the file to fs->proxy_args.
716 * 1 : buf = Buffer to use.
717 * 2 : buflen = Size of buffer in bytes.
718 * 3 : fp = File to read from
719 * 4 : fs = File will be written to fs->proxy_args. May
720 * be NULL to disable this feature.
722 * Returns : NULL on EOF or error
723 * Otherwise, returns buf.
725 *********************************************************************/
726 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
729 char linebuf[BUFSIZ];
731 while (fgets(linebuf, sizeof(linebuf), fp))
733 #ifndef SPLIT_PROXY_ARGS
734 if (fs && !suppress_blocklists)
736 char *html_line = html_encode(linebuf);
737 if (html_line != NULL)
739 fs->proxy_args = strsav(fs->proxy_args, html_line);
742 fs->proxy_args = strsav(fs->proxy_args, "<br>");
744 #endif /* ndef SPLIT_PROXY_ARGS */
746 /* Trim off newline and any comment */
747 if ((p = strpbrk(linebuf, "\r\n#")) != NULL)
752 /* Trim leading whitespace */
754 while (*p && ijb_isspace(*p))
761 /* There is something other than whitespace on the line. */
763 /* Move the data to the start of buf */
766 /* strcpy that can cope with overlap. */
768 while ((*q++ = *p++) != '\0')
774 /* Trim trailing whitespace */
775 p = linebuf + strlen(linebuf) - 1;
778 * Note: the (p >= linebuf) below is paranoia, it's not really needed.
779 * When p == linebuf then ijb_isspace(*p) will be false and we'll drop
782 while ((p >= linebuf) && ijb_isspace(*p))
788 /* More paranoia. This if statement is always true. */
791 strcpy(buf, linebuf);
803 /*********************************************************************
805 * Function : load_aclfile
807 * Description : Read and parse an aclfile and add to files list.
810 * 1 : csp = Current client state (buffers, headers, etc...)
812 * Returns : 0 => Ok, everything else is an error.
814 *********************************************************************/
815 int load_aclfile(struct client_state *csp)
818 char buf[BUFSIZ], *v[3], *p;
820 struct access_control_list *a, *bl;
821 struct file_list *fs;
823 if (!check_file_changed(current_aclfile, aclfile, &fs))
825 /* No need to load */
828 csp->alist = current_aclfile;
834 goto load_aclfile_error;
837 fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
842 goto load_aclfile_error;
845 fp = fopen(aclfile, "r");
849 goto load_aclfile_error;
852 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
854 i = ssplit(buf, " \t", v, SZ(v), 1, 1);
856 /* allocate a new node */
857 a = (struct access_control_list *) zalloc(sizeof(*a));
865 goto load_aclfile_error;
868 /* add it to the list */
875 if (acl_addr(v[2], a->dst) < 0)
877 goto load_aclfile_error;
882 if (acl_addr(v[1], a->src) < 0)
884 goto load_aclfile_error;
888 if (strcmpic(p, "permit") == 0)
890 a->action = ACL_PERMIT;
894 if (strcmpic(p, "deny") == 0)
896 a->action = ACL_DENY;
902 goto load_aclfile_error;
908 #ifndef SPLIT_PROXY_ARGS
909 if (!suppress_blocklists)
911 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
913 #endif /* ndef SPLIT_PROXY_ARGS */
917 current_aclfile->unloader = unload_aclfile;
920 fs->next = files->next;
922 current_aclfile = fs;
932 log_error(LOG_LEVEL_ERROR, "can't load access control list %s: %E", aclfile);
936 #endif /* def ACL_FILES */
939 /*********************************************************************
941 * Function : load_blockfile
943 * Description : Read and parse a blockfile and add to files list.
946 * 1 : csp = Current client state (buffers, headers, etc...)
948 * Returns : 0 => Ok, everything else is an error.
950 *********************************************************************/
951 int load_blockfile(struct client_state *csp)
955 struct block_spec *b, *bl;
956 char buf[BUFSIZ], *p, *q;
958 struct file_list *fs;
960 if (!check_file_changed(current_blockfile, blockfile, &fs))
962 /* No need to load */
965 csp->blist = current_blockfile;
971 goto load_blockfile_error;
974 fs->f = bl = (struct block_spec *) zalloc(sizeof(*bl));
977 goto load_blockfile_error;
980 if ((fp = fopen(blockfile, "r")) == NULL)
982 goto load_blockfile_error;
985 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
994 while ((*p++ = *q++))
1000 /* skip lines containing only ~ */
1006 /* allocate a new node */
1007 if ((b = zalloc(sizeof(*b))) == NULL)
1010 goto load_blockfile_error;
1013 /* add it to the list */
1019 /* Save the URL pattern */
1020 if (create_url_spec(b->url, buf))
1023 goto load_blockfile_error;
1029 #ifndef SPLIT_PROXY_ARGS
1030 if (!suppress_blocklists)
1032 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1034 #endif /* ndef SPLIT_PROXY_ARGS */
1036 /* the old one is now obsolete */
1037 if (current_blockfile)
1039 current_blockfile->unloader = unload_blockfile;
1042 fs->next = files->next;
1044 current_blockfile = fs;
1053 load_blockfile_error:
1054 log_error(LOG_LEVEL_ERROR, "can't load blockfile '%s': %E", blockfile);
1060 #ifdef USE_IMAGE_LIST
1061 /*********************************************************************
1063 * Function : load_imagefile
1065 * Description : Read and parse an imagefile and add to files list.
1068 * 1 : csp = Current client state (buffers, headers, etc...)
1070 * Returns : 0 => Ok, everything else is an error.
1072 *********************************************************************/
1073 int load_imagefile(struct client_state *csp)
1077 struct block_spec *b, *bl;
1078 char buf[BUFSIZ], *p, *q;
1080 struct file_list *fs;
1082 if (!check_file_changed(current_imagefile, imagefile, &fs))
1084 /* No need to load */
1087 csp->ilist = current_imagefile;
1093 goto load_imagefile_error;
1096 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1099 goto load_imagefile_error;
1102 if ((fp = fopen(imagefile, "r")) == NULL)
1104 goto load_imagefile_error;
1107 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1116 while ((*p++ = *q++))
1122 /* skip lines containing only ~ */
1128 /* allocate a new node */
1129 if ((b = zalloc(sizeof(*b))) == NULL)
1132 goto load_imagefile_error;
1135 /* add it to the list */
1141 /* Save the URL pattern */
1142 if (create_url_spec(b->url, buf))
1145 goto load_imagefile_error;
1151 #ifndef SPLIT_PROXY_ARGS
1152 if (!suppress_blocklists)
1154 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1156 #endif /* ndef SPLIT_PROXY_ARGS */
1158 /* the old one is now obsolete */
1159 if (current_imagefile)
1161 current_imagefile->unloader = unload_imagefile;
1164 fs->next = files->next;
1166 current_imagefile = fs;
1175 load_imagefile_error:
1176 log_error(LOG_LEVEL_ERROR, "can't load imagefile '%s': %E", imagefile);
1180 #endif /* def USE_IMAGE_LIST */
1183 /*********************************************************************
1185 * Function : load_permissions_file
1187 * Description : Read and parse a permissions file and add to files
1191 * 1 : csp = Current client state (buffers, headers, etc...)
1193 * Returns : 0 => Ok, everything else is an error.
1195 *********************************************************************/
1196 int load_permissions_file(struct client_state *csp)
1200 struct permissions_spec *b, *bl;
1201 char buf[BUFSIZ], *p, *q;
1203 struct file_list *fs;
1206 if (!check_file_changed(current_permissions_file, permissions_file, &fs))
1208 /* No need to load */
1211 csp->permissions_list = current_permissions_file;
1217 goto load_permissions_error;
1220 fs->f = bl = (struct permissions_spec *)zalloc(sizeof(*bl));
1223 goto load_permissions_error;
1226 if ((fp = fopen(permissions_file, "r")) == NULL)
1228 goto load_permissions_error;
1233 * default_permissions is set in this file.
1235 * Reset it to default first.
1237 default_permissions = PERMIT_RE_FILTER;
1239 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1243 permissions = PERMIT_COOKIE_SET | PERMIT_COOKIE_READ | PERMIT_POPUPS;
1246 * FIXME: for() loop is a kludge. Want to loop around until we
1247 * find a non-control character. Assume there will be at most 4
1250 for (i = 0; i < 4; i++)
1256 * Allow cookies to be read by the server, but do
1257 * not allow them to be set.
1259 permissions = (permissions & ~PERMIT_COOKIE_SET);
1265 * Allow server to set cookies but do not let the
1268 permissions = (permissions & ~PERMIT_COOKIE_READ);
1276 permissions = (permissions & ~PERMIT_POPUPS);
1282 * Permit filtering using PCRS
1284 permissions = (permissions | PERMIT_RE_FILTER);
1290 * All of the above (maximum filtering).
1292 permissions = PERMIT_RE_FILTER;
1298 * FIXME: Should break out of the loop here.
1305 * Elide any of the "special" chars from the
1306 * front of the pattern
1311 while ((*q++ = *p++) != '\0')
1317 /* a lines containing only "special" chars sets default */
1320 default_permissions = permissions;
1324 /* allocate a new node */
1325 if (((b = zalloc(sizeof(*b))) == NULL)
1329 goto load_permissions_error;
1332 /* add it to the list */
1337 b->permissions = permissions;
1339 /* Save the URL pattern */
1340 if (create_url_spec(b->url, buf))
1343 goto load_permissions_error;
1349 #ifndef SPLIT_PROXY_ARGS
1350 if (!suppress_blocklists)
1352 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1354 #endif /* ndef SPLIT_PROXY_ARGS */
1356 /* the old one is now obsolete */
1357 if (current_permissions_file)
1359 current_permissions_file->unloader = unload_permissions_file;
1362 fs->next = files->next;
1364 current_permissions_file = fs;
1368 csp->permissions_list = fs;
1373 load_permissions_error:
1374 log_error(LOG_LEVEL_ERROR, "can't load permissions file '%s': %E", permissions_file);
1381 /*********************************************************************
1383 * Function : load_trustfile
1385 * Description : Read and parse a trustfile and add to files list.
1388 * 1 : csp = Current client state (buffers, headers, etc...)
1390 * Returns : 0 => Ok, everything else is an error.
1392 *********************************************************************/
1393 int load_trustfile(struct client_state *csp)
1397 struct block_spec *b, *bl;
1398 struct url_spec **tl;
1400 char buf[BUFSIZ], *p, *q;
1401 int reject, trusted;
1402 struct file_list *fs;
1404 if (!check_file_changed(current_trustfile, trustfile, &fs))
1406 /* No need to load */
1409 csp->tlist = current_trustfile;
1415 goto load_trustfile_error;
1418 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1421 goto load_trustfile_error;
1424 if ((fp = fopen(trustfile, "r")) == NULL)
1426 goto load_trustfile_error;
1431 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1447 while ((*p++ = *q++))
1453 /* skip blank lines */
1459 /* allocate a new node */
1460 if ((b = zalloc(sizeof(*b))) == NULL)
1463 goto load_trustfile_error;
1466 /* add it to the list */
1472 /* Save the URL pattern */
1473 if (create_url_spec(b->url, buf))
1476 goto load_trustfile_error;
1480 * save a pointer to URL's spec in the list of trusted URL's, too
1492 #ifndef SPLIT_PROXY_ARGS
1493 if (!suppress_blocklists)
1495 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1497 #endif /* ndef SPLIT_PROXY_ARGS */
1499 /* the old one is now obsolete */
1500 if (current_trustfile)
1502 current_trustfile->unloader = unload_trustfile;
1505 fs->next = files->next;
1507 current_trustfile = fs;
1516 load_trustfile_error:
1517 log_error(LOG_LEVEL_ERROR, "can't load trustfile '%s': %E", trustfile);
1521 #endif /* def TRUST_FILES */
1524 /*********************************************************************
1526 * Function : load_forwardfile
1528 * Description : Read and parse a forwardfile and add to files list.
1531 * 1 : csp = Current client state (buffers, headers, etc...)
1533 * Returns : 0 => Ok, everything else is an error.
1535 *********************************************************************/
1536 int load_forwardfile(struct client_state *csp)
1540 struct forward_spec *b, *bl;
1541 char buf[BUFSIZ], *p, *q, *tmp;
1543 int port, n, reject;
1544 struct file_list *fs;
1545 const struct gateway *gw;
1546 struct url_spec url[1];
1548 if (!check_file_changed(current_forwardfile, forwardfile, &fs))
1550 /* No need to load */
1553 csp->flist = current_forwardfile;
1559 goto load_forwardfile_error;
1562 fs->f = bl = (struct forward_spec *)zalloc(sizeof(*bl));
1564 if ((fs == NULL) || (bl == NULL))
1566 goto load_forwardfile_error;
1569 if ((fp = fopen(forwardfile, "r")) == NULL)
1571 goto load_forwardfile_error;
1576 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1582 n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1586 log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1590 strcpy(buf, vec[0]);
1599 while ((*p++ = *q++))
1605 /* skip lines containing only ~ */
1611 /* allocate a new node */
1612 if (((b = zalloc(sizeof(*b))) == NULL)
1614 || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
1619 goto load_forwardfile_error;
1622 /* add it to the list */
1626 /* save a copy of the orignal specification */
1627 if ((b->url->spec = strdup(buf)) == NULL)
1630 goto load_forwardfile_error;
1635 if ((p = strchr(buf, '/')))
1637 b->url->path = strdup(p);
1638 b->url->pathlen = strlen(b->url->path);
1643 b->url->path = NULL;
1644 b->url->pathlen = 0;
1652 sprintf(rebuf, "^(%s)", b->url->path);
1654 errcode = regcomp(b->url->preg, rebuf,
1655 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
1659 size_t errlen = regerror(errcode, b->url->preg, buf, sizeof(buf));
1663 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
1666 goto load_forwardfile_error;
1671 freez(b->url->preg);
1674 if ((p = strchr(buf, ':')) == NULL)
1684 b->url->port = port;
1686 if ((b->url->domain = strdup(buf)) == NULL)
1689 goto load_forwardfile_error;
1692 /* split domain into components */
1693 *url = dsplit(b->url->domain);
1694 b->url->dbuf = url->dbuf;
1695 b->url->dcnt = url->dcnt;
1696 b->url->dvec = url->dvec;
1698 /* now parse the gateway specs */
1702 for (gw = gateways; gw->name; gw++)
1704 if (strcmp(gw->name, p) == 0)
1710 if (gw->name == NULL)
1712 goto load_forwardfile_error;
1715 /* save this as the gateway type */
1718 /* now parse the gateway host[:port] spec */
1721 if (strcmp(p, ".") != 0)
1723 b->gw->gateway_host = strdup(p);
1725 if ((p = strchr(b->gw->gateway_host, ':')))
1728 b->gw->gateway_port = atoi(p);
1731 if (b->gw->gateway_port <= 0)
1733 goto load_forwardfile_error;
1737 /* now parse the forwarding spec */
1740 if (strcmp(p, ".") != 0)
1742 b->gw->forward_host = strdup(p);
1744 if ((p = strchr(b->gw->forward_host, ':')))
1747 b->gw->forward_port = atoi(p);
1750 if (b->gw->forward_port <= 0)
1752 b->gw->forward_port = 8000;
1761 #ifndef SPLIT_PROXY_ARGS
1762 if (!suppress_blocklists)
1764 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1766 #endif /* ndef SPLIT_PROXY_ARGS */
1768 /* the old one is now obsolete */
1769 if (current_forwardfile)
1771 current_forwardfile->unloader = unload_forwardfile;
1774 fs->next = files->next;
1776 current_forwardfile = fs;
1785 load_forwardfile_error:
1786 log_error(LOG_LEVEL_ERROR, "can't load forwardfile '%s': %E", forwardfile);
1793 /*********************************************************************
1795 * Function : load_re_filterfile
1797 * Description : Load the re_filterfile. Each non-comment, non-empty
1798 * line is instantly added to the joblist, which is
1799 * a chained list of pcrs_job structs.
1802 * 1 : csp = Current client state (buffers, headers, etc...)
1804 * Returns : 0 => Ok, everything else is an error.
1806 *********************************************************************/
1807 int load_re_filterfile(struct client_state *csp)
1811 struct re_filterfile_spec *bl;
1812 struct file_list *fs;
1818 if (!check_file_changed(current_re_filterfile, re_filterfile, &fs))
1820 /* No need to load */
1823 csp->rlist = current_re_filterfile;
1829 goto load_re_filterfile_error;
1832 fs->f = bl = (struct re_filterfile_spec *)zalloc(sizeof(*bl));
1835 goto load_re_filterfile_error;
1838 /* Open the file or fail */
1839 if ((fp = fopen(re_filterfile, "r")) == NULL)
1841 goto load_re_filterfile_error;
1844 /* Read line by line */
1845 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1847 enlist( bl->patterns, buf );
1849 /* We have a meaningful line -> make it a job */
1850 if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1852 log_error(LOG_LEVEL_RE_FILTER,
1853 "Adding re_filter job %s failed with error %d.", buf, error);
1858 dummy->next = bl->joblist;
1859 bl->joblist = dummy;
1860 log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1866 #ifndef SPLIT_PROXY_ARGS
1867 if (!suppress_blocklists)
1869 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1871 #endif /* ndef SPLIT_PROXY_ARGS */
1873 /* the old one is now obsolete */
1874 if ( NULL != current_re_filterfile )
1876 current_re_filterfile->unloader = unload_re_filterfile;
1879 fs->next = files->next;
1881 current_re_filterfile = fs;
1890 load_re_filterfile_error:
1891 log_error(LOG_LEVEL_ERROR, "can't load re_filterfile '%s': %E", 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.
1911 *********************************************************************/
1912 void add_loader(int (*loader)(struct client_state *))
1916 for (i=0; i < NLOADERS; i++)
1918 if (loaders[i] == NULL)
1920 loaders[i] = loader;
1928 /*********************************************************************
1930 * Function : run_loader
1932 * Description : Called from `load_config' and `listen_loop'. This
1933 * function keeps the "csp" current with any file mods
1934 * since the last loop. If a file is unchanged, the
1935 * loader functions do NOT reload the file.
1938 * 1 : csp = Current client state (buffers, headers, etc...)
1940 * Returns : 0 => Ok, everything else is an error.
1942 *********************************************************************/
1943 int run_loader(struct client_state *csp)
1948 for (i=0; i < NLOADERS; i++)
1950 if (loaders[i] == NULL)
1954 ret |= (loaders[i])(csp);
1961 /*********************************************************************
1963 * Function : remove_all_loaders
1965 * Description : Remove all loaders from the list.
1971 *********************************************************************/
1972 void remove_all_loaders(void)
1974 memset( loaders, 0, sizeof( loaders ) );