1 const char loaders_rcs[] = "$Id: loaders.c,v 1.9 2001/05/26 17:12:07 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.9 2001/05/26 17:12:07 jongfoster
39 * Fatal errors loading configuration files now give better error messages.
41 * Revision 1.8 2001/05/26 00:55:20 jongfoster
42 * Removing duplicated code. load_forwardfile() now uses create_url_spec()
44 * Revision 1.7 2001/05/26 00:28:36 jongfoster
45 * Automatic reloading of config file.
46 * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
47 * Most of the global variables have been moved to a new
48 * struct configuration_spec, accessed through csp->config->globalname
49 * Most of the globals remaining are used by the Win32 GUI.
51 * Revision 1.6 2001/05/23 12:27:33 oes
53 * Fixed ugly indentation of my last changes
55 * Revision 1.5 2001/05/23 10:39:05 oes
56 * - Added support for escaping the comment character
57 * in config files by a backslash
58 * - Added support for line continuation in config
60 * - Fixed a buffer overflow bug with long config lines
62 * Revision 1.4 2001/05/22 18:56:28 oes
65 * Revision 1.3 2001/05/20 01:21:20 jongfoster
66 * Version 2.9.4 checkin.
67 * - Merged popupfile and cookiefile, and added control over PCRS
68 * filtering, in new "permissionsfile".
69 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
70 * file error you now get a message box (in the Win32 GUI) rather
71 * than the program exiting with no explanation.
72 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
74 * - Removed tabs from "config"
75 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
76 * - Bumped up version number.
78 * Revision 1.2 2001/05/17 23:01:01 oes
79 * - Cleaned CRLF's from the sources and related files
81 * Revision 1.1.1.1 2001/05/15 13:58:59 oes
82 * Initial import of version 2.9.3 source tree
85 *********************************************************************/
92 #include <sys/types.h>
110 #include "miscutil.h"
114 #ifndef SPLIT_PROXY_ARGS
116 #include "showargs.h"
117 #endif /* ndef SPLIT_PROXY_ARGS */
119 const char loaders_h_rcs[] = LOADERS_H_VERSION;
121 /* Fix a problem with Solaris. There should be no effect on other
123 * Solaris's isspace() is a macro which uses it's argument directly
124 * as an array index. Therefore we need to make sure that high-bit
125 * characters generate +ve values, and ideally we also want to make
126 * the argument match the declared parameter type of "int".
128 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
132 * Currently active files.
133 * These are also entered in the main linked list of files.
135 static struct file_list *current_permissions_file = NULL;
136 static struct file_list *current_forwardfile = NULL;
139 static struct file_list *current_aclfile = NULL;
140 #endif /* def ACL_FILES */
143 static struct file_list *current_trustfile = NULL;
144 #endif /* def TRUST_FILES */
147 static struct file_list *current_re_filterfile = NULL;
148 #endif /* def PCRS */
151 static int create_url_spec(struct url_spec * url, char * buf);
154 /*********************************************************************
158 * Description : Basically a mark and sweep garbage collector, it is run
159 * (by the parent thread) every once in a while to reclaim memory.
161 * It uses a mark and sweep strategy:
162 * 1) mark all files as inactive
164 * 2) check with each client:
165 * if it is active, mark its files as active
166 * if it is inactive, free its resources
168 * 3) free the resources of all of the files that
169 * are still marked as inactive (and are obsolete).
171 * N.B. files that are not obsolete don't have an unloader defined.
177 *********************************************************************/
180 struct file_list *fl, *nfl;
181 struct client_state *csp, *ncsp;
183 /* clear all of the file's active flags */
184 for ( fl = files->next; NULL != fl; fl = fl->next )
189 for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
193 /* mark this client's files as active */
196 * Always have a configuration file.
197 * (Also note the slightly non-standard extra
200 ncsp->config->config_file_list->active = 1;
202 if (ncsp->permissions_list) /* permissions files */
204 ncsp->permissions_list->active = 1;
207 if (ncsp->flist) /* forward files */
209 ncsp->flist->active = 1;
213 if (ncsp->alist) /* acl files */
215 ncsp->alist->active = 1;
217 #endif /* def ACL_FILES */
220 if (ncsp->rlist) /* perl re files */
222 ncsp->rlist->active = 1;
224 #endif /* def PCRS */
227 if (ncsp->tlist) /* trust files */
229 ncsp->tlist->active = 1;
231 #endif /* def TRUST_FILES */
236 /* this client one is not active, release its resources */
237 csp->next = ncsp->next;
239 freez(ncsp->ip_addr_str);
241 freez(ncsp->referrer);
242 #endif /* def TRUST_FILES */
243 freez(ncsp->x_forwarded);
244 freez(ncsp->iob->buf);
246 free_http_request(ncsp->http);
248 destroy_list(ncsp->headers);
249 destroy_list(ncsp->cookie_list);
257 #endif /* def STATISTICS */
263 for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
265 if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
267 fl->next = nfl->next;
269 (nfl->unloader)(nfl->f);
271 #ifndef SPLIT_PROXY_ARGS
272 freez(nfl->proxy_args);
273 #endif /* ndef SPLIT_PROXY_ARGS */
275 freez(nfl->filename);
284 /*********************************************************************
286 * Function : create_url_spec
288 * Description : Creates a "url_spec" structure from a string.
289 * When finished, free with unload_url().
292 * 1 : url = Target url_spec to be filled in. Must be
293 * zeroed out before the call (e.g. using zalloc).
294 * 2 : buf = Source pattern, null terminated. NOTE: The
295 * contents of this buffer are destroyed by this
296 * function. If this function succeeds, the
297 * buffer is copied to url->spec. If this
298 * function fails, the contents of the buffer
301 * Returns : 0 => Ok, everything else is an error.
303 *********************************************************************/
304 static int create_url_spec(struct url_spec * url, char * buf)
307 struct url_spec tmp_url[1];
309 /* paranoia - should never happen. */
310 if ((url == NULL) || (buf == NULL))
315 /* save a copy of the orignal specification */
316 if ((url->spec = strdup(buf)) == NULL)
321 if ((p = strchr(buf, '/')))
323 if (NULL == (url->path = strdup(p)))
328 url->pathlen = strlen(url->path);
342 if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
349 sprintf(rebuf, "^(%s)", url->path);
351 errcode = regcomp(url->preg, rebuf,
352 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
357 url->preg, buf, sizeof(buf));
361 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
372 if ((p = strchr(buf, ':')) == NULL)
382 if ((url->domain = strdup(buf)) == NULL)
388 #endif /* def REGEX */
392 /* split domain into components */
394 *tmp_url = dsplit(url->domain);
395 url->dbuf = tmp_url->dbuf;
396 url->dcnt = tmp_url->dcnt;
397 url->dvec = tmp_url->dvec;
403 /*********************************************************************
405 * Function : unload_url
407 * Description : Called from the "unloaders". Freez the url
408 * structure elements.
411 * 1 : url = pointer to a url_spec structure.
415 *********************************************************************/
416 static void unload_url(struct url_spec *url)
418 if (url == NULL) return;
437 /*********************************************************************
439 * Function : unload_aclfile
441 * Description : Unloads an aclfile.
444 * 1 : f = the data structure associated with the aclfile.
448 *********************************************************************/
449 static void unload_aclfile(void *f)
451 struct access_control_list *b = (struct access_control_list *)f;
452 if (b == NULL) return;
454 unload_aclfile(b->next);
459 #endif /* def ACL_FILES */
462 /*********************************************************************
464 * Function : unload_permissions_file
466 * Description : Unloads a permissions file.
469 * 1 : file_data = the data structure associated with the
474 *********************************************************************/
475 static void unload_permissions_file(void *file_data)
477 struct permissions_spec * next;
478 struct permissions_spec * cur = (struct permissions_spec *)file_data;
482 unload_url(cur->url);
491 /*********************************************************************
493 * Function : unload_trustfile
495 * Description : Unloads a trustfile.
498 * 1 : f = the data structure associated with the trustfile.
502 *********************************************************************/
503 static void unload_trustfile(void *f)
505 struct block_spec *b = (struct block_spec *)f;
506 if (b == NULL) return;
508 unload_trustfile(b->next);
515 #endif /* def TRUST_FILES */
518 /*********************************************************************
520 * Function : unload_forwardfile
522 * Description : Unloads a forwardfile.
525 * 1 : f = the data structure associated with the forwardfile.
529 *********************************************************************/
530 static void unload_forwardfile(void *f)
532 struct forward_spec *b = (struct forward_spec *)f;
533 if (b == NULL) return;
535 unload_forwardfile(b->next);
539 freez(b->gw->gateway_host);
540 freez(b->gw->forward_host);
548 /*********************************************************************
550 * Function : unload_re_filterfile
552 * Description : Unload the re_filter list.
555 * 1 : f = the data structure associated with the filterfile.
559 *********************************************************************/
560 static void unload_re_filterfile(void *f)
563 struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
565 if (b == NULL) return;
567 destroy_list(b->patterns);
569 joblist = b->joblist;
570 while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
575 #endif /* def PCRS */
578 /*********************************************************************
580 * Function : check_file_changed
582 * Description : Helper function to check if a file needs reloading.
583 * If "current" is still current, return it. Otherwise
584 * allocates a new (zeroed) "struct file_list", fills
585 * in the disk file name and timestamp, and returns it.
588 * 1 : current = The file_list currently being used - will
589 * be checked to see if it is out of date.
590 * May be NULL (which is treated as out of
592 * 2 : filename = Name of file to check.
593 * 3 : newfl = New file list. [Output only]
594 * This will be set to NULL, OR a struct
595 * file_list newly allocated on the
596 * heap, with the filename and lastmodified
597 * fields filled, standard header giving file
598 * name in proxy_args, and all others zeroed.
599 * (proxy_args is only filled in if !defined
600 * SPLIT_PROXY_ARGS and !suppress_blocklists).
602 * Returns : If file unchanged: 0 (and sets newfl == NULL)
603 * If file changed: 1 and sets newfl != NULL
604 * On error: 1 and sets newfl == NULL
606 *********************************************************************/
607 int check_file_changed(const struct file_list * current,
608 const char * filename,
609 struct file_list ** newfl)
611 struct file_list *fs;
612 struct stat statbuf[1];
616 if (stat(filename, statbuf) < 0)
618 /* Error, probably file not found. */
623 && (current->lastmodified == statbuf->st_mtime)
624 && (0 == strcmp(current->filename, filename)))
629 fs = (struct file_list *)zalloc(sizeof(struct file_list));
633 /* Out of memory error */
637 fs->filename = strdup(filename);
638 fs->lastmodified = statbuf->st_mtime;
640 if (fs->filename == NULL)
642 /* Out of memory error */
647 #ifndef SPLIT_PROXY_ARGS
648 if (!suppress_blocklists)
650 char * p = html_encode(filename);
653 fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
654 fs->proxy_args = strsav(fs->proxy_args, p);
655 fs->proxy_args = strsav(fs->proxy_args,
656 "' contains the following patterns</h2>\n");
659 fs->proxy_args = strsav(fs->proxy_args, "<pre>");
661 #endif /* ndef SPLIT_PROXY_ARGS */
668 /*********************************************************************
670 * Function : read_config_line
672 * Description : Read a single non-empty line from a file and return
673 * it. Trims comments, leading and trailing whitespace
674 * and respects escaping of newline and comment char.
675 * Also writes the file to fs->proxy_args.
678 * 1 : buf = Buffer to use.
679 * 2 : buflen = Size of buffer in bytes.
680 * 3 : fp = File to read from
681 * 4 : fs = File will be written to fs->proxy_args. May
682 * be NULL to disable this feature.
684 * Returns : NULL on EOF or error
685 * Otherwise, returns buf.
687 *********************************************************************/
688 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
691 char linebuf[BUFSIZ];
696 while (fgets(linebuf, sizeof(linebuf), fp))
698 #ifndef SPLIT_PROXY_ARGS
699 if (fs && !suppress_blocklists)
701 char *html_line = html_encode(linebuf);
702 if (html_line != NULL)
704 fs->proxy_args = strsav(fs->proxy_args, html_line);
707 fs->proxy_args = strsav(fs->proxy_args, "<br>");
709 #endif /* ndef SPLIT_PROXY_ARGS */
711 /* Trim off newline */
712 if ((p = strpbrk(linebuf, "\r\n")) != NULL)
717 /* Line continuation? Trim escape and set flag. */
718 if ((p != linebuf) && (*--p == '\\'))
724 /* If there's a comment char.. */
725 if ((p = strpbrk(linebuf, "#")) != NULL)
727 /* ..and it's escaped, left-shift the line over the escape. */
728 if ((p != linebuf) && (*(p-1) == '\\'))
731 while ((*q++ = *p++) != '\0') /* nop */;
733 /* Else, chop off the rest of the line */
740 /* Trim leading whitespace */
742 while (*p && ijb_isspace(*p))
749 /* There is something other than whitespace on the line. */
751 /* Move the data to the start of buf */
754 /* strcpy that can cope with overlap. */
756 while ((*q++ = *p++) != '\0')
762 /* Trim trailing whitespace */
763 p = linebuf + strlen(linebuf) - 1;
766 * Note: the (p >= linebuf) below is paranoia, it's not really needed.
767 * When p == linebuf then ijb_isspace(*p) will be false and we'll drop
770 while ((p >= linebuf) && ijb_isspace(*p))
776 /* More paranoia. This if statement is always true. */
779 strncat(buf, linebuf, buflen - strlen(buf));
799 /*********************************************************************
801 * Function : load_aclfile
803 * Description : Read and parse an aclfile and add to files list.
806 * 1 : csp = Current client state (buffers, headers, etc...)
808 * Returns : 0 => Ok, everything else is an error.
810 *********************************************************************/
811 int load_aclfile(struct client_state *csp)
814 char buf[BUFSIZ], *v[3], *p;
816 struct access_control_list *a, *bl;
817 struct file_list *fs;
819 if (!check_file_changed(current_aclfile, csp->config->aclfile, &fs))
821 /* No need to load */
824 csp->alist = current_aclfile;
830 goto load_aclfile_error;
833 fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
838 goto load_aclfile_error;
841 fp = fopen(csp->config->aclfile, "r");
845 goto load_aclfile_error;
848 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
850 i = ssplit(buf, " \t", v, SZ(v), 1, 1);
852 /* allocate a new node */
853 a = (struct access_control_list *) zalloc(sizeof(*a));
861 goto load_aclfile_error;
864 /* add it to the list */
871 if (acl_addr(v[2], a->dst) < 0)
873 goto load_aclfile_error;
878 if (acl_addr(v[1], a->src) < 0)
880 goto load_aclfile_error;
884 if (strcmpic(p, "permit") == 0)
886 a->action = ACL_PERMIT;
890 if (strcmpic(p, "deny") == 0)
892 a->action = ACL_DENY;
898 goto load_aclfile_error;
904 #ifndef SPLIT_PROXY_ARGS
905 if (!suppress_blocklists)
907 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
909 #endif /* ndef SPLIT_PROXY_ARGS */
913 current_aclfile->unloader = unload_aclfile;
916 fs->next = files->next;
918 current_aclfile = fs;
928 log_error(LOG_LEVEL_FATAL, "can't load access control list %s: %E",
929 csp->config->aclfile);
933 #endif /* def ACL_FILES */
936 struct permission_alias
939 unsigned mask; /* a bit set to "0" = remove permission */
940 unsigned add; /* a bit set to "1" = add permission */
941 struct permission_alias * next;
946 * Note: this is special-cased in the code so we don't need to
947 * fill in the ->next fields.
949 static const struct permission_alias standard_aliases[] =
951 { "+block", PERMIT_MASK_ALL, PERMIT_BLOCK },
952 /* { "+cookies", PERMIT_MASK_ALL, PERMIT_COOKIE_SET | PERMIT_COOKIE_READ }, */
953 { "+cookies-read", PERMIT_MASK_ALL, PERMIT_COOKIE_READ },
954 { "+cookies-set", PERMIT_MASK_ALL, PERMIT_COOKIE_SET },
955 { "+fast-redirects", PERMIT_MASK_ALL, PERMIT_FAST_REDIRECTS },
956 { "+filter", PERMIT_MASK_ALL, PERMIT_RE_FILTER },
957 { "+image", PERMIT_MASK_ALL, PERMIT_IMAGE },
958 { "+popup", PERMIT_MASK_ALL, PERMIT_POPUPS },
959 { "+popups", PERMIT_MASK_ALL, PERMIT_POPUPS },
960 { "+referer", PERMIT_MASK_ALL, PERMIT_REFERER },
961 { "+referrer", PERMIT_MASK_ALL, PERMIT_REFERER },
962 { "-block", ~PERMIT_BLOCK, 0 },
963 /* { "-cookies", ~(PERMIT_COOKIE_SET | PERMIT_COOKIE_READ), 0 }, */
964 { "-cookies-read", ~PERMIT_COOKIE_READ, 0 },
965 { "-cookies-set", ~PERMIT_COOKIE_SET, 0 },
966 { "-fast-redirects", ~PERMIT_FAST_REDIRECTS, 0 },
967 { "-filter", ~PERMIT_RE_FILTER, 0 },
968 { "-image", ~PERMIT_IMAGE, 0 },
969 { "-popup", ~PERMIT_POPUPS, 0 },
970 { "-popups", ~PERMIT_POPUPS, 0 },
971 { "-referer", ~PERMIT_REFERER, 0 },
972 { "-referrer", ~PERMIT_REFERER, 0 },
973 { NULL, 0, 0 } /* End marker */
977 /*********************************************************************
979 * Function : load_permissions_file
981 * Description : Read and parse a permissions file and add to files
985 * 1 : csp = Current client state (buffers, headers, etc...)
987 * Returns : 0 => Ok, everything else is an error.
989 *********************************************************************/
990 int load_permissions_file(struct client_state *csp)
994 struct permissions_spec *last_perm;
995 struct permissions_spec *perm;
997 struct file_list *fs;
998 #define MODE_START_OF_FILE 1
999 #define MODE_PERMISSIONS 2
1000 #define MODE_ALIAS 3
1001 int mode = MODE_START_OF_FILE;
1002 unsigned curmask = PERMIT_MASK_ALL;
1003 unsigned curadd = 0;
1004 struct permission_alias * alias_list = NULL;
1006 if (!check_file_changed(current_permissions_file, csp->config->permissions_file, &fs))
1008 /* No need to load */
1011 csp->permissions_list = current_permissions_file;
1017 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': error finding file: %E",
1018 csp->config->permissions_file);
1019 return 1; /* never get here */
1022 fs->f = last_perm = (struct permissions_spec *)zalloc(sizeof(*last_perm));
1023 if (last_perm == NULL)
1025 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': out of memory!",
1026 csp->config->permissions_file);
1027 return 1; /* never get here */
1030 if ((fp = fopen(csp->config->permissions_file, "r")) == NULL)
1032 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': error opening file: %E",
1033 csp->config->permissions_file);
1034 return 1; /* never get here */
1037 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1041 /* It's a header block */
1044 /* It's {{settings}} or {{alias}} */
1045 int len = strlen(buf);
1046 char * start = buf + 2;
1047 char * end = buf + len - 1;
1048 if ((len < 5) || (*end-- != '}') || (*end-- != '}'))
1052 log_error(LOG_LEVEL_FATAL,
1053 "can't load permissions file '%s': invalid line: %s",
1054 csp->config->permissions_file, buf);
1055 return 1; /* never get here */
1058 /* Trim leading and trailing whitespace. */
1059 while ((*end == ' ') || (*end == '\t'))
1062 * don't need to worry about going off front of string
1063 * because we know there's a '{' there.
1068 while ((*start == ' ') || (*start == '\t'))
1077 log_error(LOG_LEVEL_FATAL,
1078 "can't load permissions file '%s': invalid line: {{ }}",
1079 csp->config->permissions_file);
1080 return 1; /* never get here */
1083 if (0 == strcmpic(start, "alias"))
1085 /* it's an {{alias}} block */
1091 /* invalid {{something}} block */
1093 log_error(LOG_LEVEL_FATAL,
1094 "can't load permissions file '%s': invalid line: {{%s}}",
1095 csp->config->permissions_file, start);
1096 return 1; /* never get here */
1101 /* It's a permissions block */
1105 int len = strlen(buf);
1106 char * start = buf + 1;
1107 char * end = buf + len - 1;
1109 if ((len < 3) || (*end-- != '}'))
1113 log_error(LOG_LEVEL_FATAL,
1114 "can't load permissions file '%s': invalid line: %s",
1115 csp->config->permissions_file, buf);
1116 return 1; /* never get here */
1119 /* Trim leading and trailing whitespace. */
1120 while ((*end == ' ') || (*end == '\t'))
1123 * don't need to worry about going off front of string
1124 * because we know there's a '{' there.
1129 while ((*start == ' ') || (*start == '\t'))
1138 log_error(LOG_LEVEL_FATAL,
1139 "can't load permissions file '%s': invalid line: { }",
1140 csp->config->permissions_file);
1141 return 1; /* never get here */
1144 mode = MODE_PERMISSIONS;
1146 curmask = PERMIT_MASK_ALL;
1151 const struct permission_alias * alias = standard_aliases;
1152 char * option = start;
1153 while ((*start != '\0') && (*start != ' ') && (*start != '\t'))
1158 more = (*start != 0);
1163 /* Eat all the whitespace between the options */
1164 while ((*start == ' ') || (*start == '\t'))
1170 /* handle option in 'option' */
1172 /* Check for standard permission name */
1173 while ( (alias->name != NULL) && (0 != strcmpic(alias->name, option)) )
1177 if (alias->name == NULL)
1179 /* try user aliases. */
1181 while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) )
1183 alias = alias->next;
1188 /* Bad permission name */
1190 log_error(LOG_LEVEL_FATAL,
1191 "can't load permissions file '%s': invalid permission name: %s",
1192 csp->config->permissions_file, option);
1193 return 1; /* never get here */
1195 curmask &= alias->mask;
1196 curadd &= alias->mask;
1197 curadd |= alias->add;
1201 else if (mode == MODE_ALIAS)
1203 /* define an alias */
1204 struct permission_alias * new_alias;
1207 char * start = strchr(buf, '=');
1210 if ((start == NULL) || (start == buf))
1212 log_error(LOG_LEVEL_FATAL,
1213 "can't load permissions file '%s': invalid alias line: %s",
1214 csp->config->permissions_file, buf);
1215 return 1; /* never get here */
1218 if ((new_alias = zalloc(sizeof(*new_alias))) == NULL)
1221 log_error(LOG_LEVEL_FATAL,
1222 "can't load permissions file '%s': out of memory!",
1223 csp->config->permissions_file);
1224 return 1; /* never get here */
1227 /* Eat any the whitespace after the '=' */
1229 while ((*start == ' ') || (*start == '\t'))
1235 log_error(LOG_LEVEL_FATAL,
1236 "can't load permissions file '%s': invalid alias line: %s",
1237 csp->config->permissions_file, buf);
1238 return 1; /* never get here */
1241 /* Eat any the whitespace before the '=' */
1243 while ((*end == ' ') || (*end == '\t'))
1246 * we already know we must have at least 1 non-ws char
1247 * at start of buf - no need to check
1253 new_alias->name = strdup(buf);
1255 curmask = PERMIT_MASK_ALL;
1260 const struct permission_alias * alias = standard_aliases;
1261 char * option = start;
1262 while ((*start != '\0') && (*start != ' ') && (*start != '\t'))
1267 more = (*start != 0);
1272 /* Eat all the whitespace between the options */
1273 while ((*start == ' ') || (*start == '\t'))
1279 /* handle option in 'option' */
1281 /* Check for standard permission name */
1282 while ( (alias->name != NULL) && (0 != strcmpic(alias->name, option)) )
1286 if (alias->name == NULL)
1288 /* try user aliases. */
1290 while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) )
1292 alias = alias->next;
1297 /* Bad permission name */
1299 log_error(LOG_LEVEL_FATAL,
1300 "can't load permissions file '%s': invalid permission name: %s",
1301 csp->config->permissions_file, option);
1302 return 1; /* never get here */
1304 curmask &= alias->mask;
1305 curadd &= alias->mask;
1306 curadd |= alias->add;
1309 /* save alias permissions */
1310 new_alias->mask = curmask;
1311 new_alias->add = curadd;
1314 new_alias->next = alias_list;
1315 alias_list = new_alias;
1317 else if (mode == MODE_PERMISSIONS)
1319 /* it's a URL pattern */
1321 /* allocate a new node */
1322 if ((perm = zalloc(sizeof(*perm))) == NULL)
1325 log_error(LOG_LEVEL_FATAL,
1326 "can't load permissions file '%s': out of memory!",
1327 csp->config->permissions_file);
1328 return 1; /* never get here */
1332 perm->mask = curmask;
1335 /* Save the URL pattern */
1336 if (create_url_spec(perm->url, buf))
1339 log_error(LOG_LEVEL_FATAL,
1340 "can't load permissions file '%s': cannot create URL permission from: %s",
1341 csp->config->permissions_file, buf);
1342 return 1; /* never get here */
1345 /* add it to the list */
1346 last_perm->next = perm;
1349 else if (mode == MODE_START_OF_FILE)
1351 /* oops - please have a {} line as 1st line in file. */
1353 log_error(LOG_LEVEL_FATAL,
1354 "can't load permissions file '%s': first line is invalid: %s",
1355 csp->config->permissions_file, buf);
1356 return 1; /* never get here */
1360 /* How did we get here? This is impossible! */
1362 log_error(LOG_LEVEL_FATAL,
1363 "can't load permissions file '%s': INTERNAL ERROR - mode = %d",
1364 csp->config->permissions_file, mode);
1365 return 1; /* never get here */
1371 while (alias_list != NULL)
1373 struct permission_alias * next = alias_list->next;
1374 freez((char *)alias_list->name);
1379 #ifndef SPLIT_PROXY_ARGS
1380 if (!suppress_blocklists)
1382 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1384 #endif /* ndef SPLIT_PROXY_ARGS */
1386 /* the old one is now obsolete */
1387 if (current_permissions_file)
1389 current_permissions_file->unloader = unload_permissions_file;
1392 fs->next = files->next;
1394 current_permissions_file = fs;
1398 csp->permissions_list = fs;
1407 /*********************************************************************
1409 * Function : load_trustfile
1411 * Description : Read and parse a trustfile and add to files list.
1414 * 1 : csp = Current client state (buffers, headers, etc...)
1416 * Returns : 0 => Ok, everything else is an error.
1418 *********************************************************************/
1419 int load_trustfile(struct client_state *csp)
1423 struct block_spec *b, *bl;
1424 struct url_spec **tl;
1426 char buf[BUFSIZ], *p, *q;
1427 int reject, trusted;
1428 struct file_list *fs;
1430 if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
1432 /* No need to load */
1435 csp->tlist = current_trustfile;
1441 goto load_trustfile_error;
1444 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1447 goto load_trustfile_error;
1450 if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
1452 goto load_trustfile_error;
1455 tl = csp->config->trust_list;
1457 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1473 while ((*p++ = *q++))
1479 /* skip blank lines */
1485 /* allocate a new node */
1486 if ((b = zalloc(sizeof(*b))) == NULL)
1489 goto load_trustfile_error;
1492 /* add it to the list */
1498 /* Save the URL pattern */
1499 if (create_url_spec(b->url, buf))
1502 goto load_trustfile_error;
1506 * save a pointer to URL's spec in the list of trusted URL's, too
1518 #ifndef SPLIT_PROXY_ARGS
1519 if (!suppress_blocklists)
1521 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1523 #endif /* ndef SPLIT_PROXY_ARGS */
1525 /* the old one is now obsolete */
1526 if (current_trustfile)
1528 current_trustfile->unloader = unload_trustfile;
1531 fs->next = files->next;
1533 current_trustfile = fs;
1542 load_trustfile_error:
1543 log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1544 csp->config->trustfile);
1548 #endif /* def TRUST_FILES */
1551 /*********************************************************************
1553 * Function : load_forwardfile
1555 * Description : Read and parse a forwardfile and add to files list.
1558 * 1 : csp = Current client state (buffers, headers, etc...)
1560 * Returns : 0 => Ok, everything else is an error.
1562 *********************************************************************/
1563 int load_forwardfile(struct client_state *csp)
1567 struct forward_spec *b, *bl;
1572 struct file_list *fs;
1573 const struct gateway *gw;
1575 if (!check_file_changed(current_forwardfile, csp->config->forwardfile, &fs))
1577 /* No need to load */
1580 csp->flist = current_forwardfile;
1586 goto load_forwardfile_error;
1589 fs->f = bl = (struct forward_spec *)zalloc(sizeof(*bl));
1591 if ((fs == NULL) || (bl == NULL))
1593 goto load_forwardfile_error;
1596 if ((fp = fopen(csp->config->forwardfile, "r")) == NULL)
1598 goto load_forwardfile_error;
1603 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1609 n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1613 log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1617 strcpy(buf, vec[0]);
1619 /* skip lines containing only ~ */
1625 /* allocate a new node */
1626 if (((b = zalloc(sizeof(*b))) == NULL)
1630 goto load_forwardfile_error;
1633 /* add it to the list */
1637 /* Save the URL pattern */
1638 if (create_url_spec(b->url, buf))
1641 goto load_forwardfile_error;
1644 /* now parse the gateway specs */
1648 for (gw = gateways; gw->name; gw++)
1650 if (strcmp(gw->name, p) == 0)
1656 if (gw->name == NULL)
1658 goto load_forwardfile_error;
1661 /* save this as the gateway type */
1664 /* now parse the gateway host[:port] spec */
1667 if (strcmp(p, ".") != 0)
1669 b->gw->gateway_host = strdup(p);
1671 if ((p = strchr(b->gw->gateway_host, ':')))
1674 b->gw->gateway_port = atoi(p);
1677 if (b->gw->gateway_port <= 0)
1679 goto load_forwardfile_error;
1683 /* now parse the forwarding spec */
1686 if (strcmp(p, ".") != 0)
1688 b->gw->forward_host = strdup(p);
1690 if ((p = strchr(b->gw->forward_host, ':')))
1693 b->gw->forward_port = atoi(p);
1696 if (b->gw->forward_port <= 0)
1698 b->gw->forward_port = 8000;
1707 #ifndef SPLIT_PROXY_ARGS
1708 if (!suppress_blocklists)
1710 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1712 #endif /* ndef SPLIT_PROXY_ARGS */
1714 /* the old one is now obsolete */
1715 if (current_forwardfile)
1717 current_forwardfile->unloader = unload_forwardfile;
1720 fs->next = files->next;
1722 current_forwardfile = fs;
1731 load_forwardfile_error:
1732 log_error(LOG_LEVEL_FATAL, "can't load forwardfile '%s': %E",
1733 csp->config->forwardfile);
1740 /*********************************************************************
1742 * Function : load_re_filterfile
1744 * Description : Load the re_filterfile. Each non-comment, non-empty
1745 * line is instantly added to the joblist, which is
1746 * a chained list of pcrs_job structs.
1749 * 1 : csp = Current client state (buffers, headers, etc...)
1751 * Returns : 0 => Ok, everything else is an error.
1753 *********************************************************************/
1754 int load_re_filterfile(struct client_state *csp)
1758 struct re_filterfile_spec *bl;
1759 struct file_list *fs;
1765 if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1767 /* No need to load */
1770 csp->rlist = current_re_filterfile;
1776 goto load_re_filterfile_error;
1779 fs->f = bl = (struct re_filterfile_spec *)zalloc(sizeof(*bl));
1782 goto load_re_filterfile_error;
1785 /* Open the file or fail */
1786 if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1788 goto load_re_filterfile_error;
1791 /* Read line by line */
1792 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1794 enlist( bl->patterns, buf );
1796 /* We have a meaningful line -> make it a job */
1797 if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1799 log_error(LOG_LEVEL_RE_FILTER,
1800 "Adding re_filter job %s failed with error %d.", buf, error);
1805 dummy->next = bl->joblist;
1806 bl->joblist = dummy;
1807 log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1813 #ifndef SPLIT_PROXY_ARGS
1814 if (!suppress_blocklists)
1816 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1818 #endif /* ndef SPLIT_PROXY_ARGS */
1820 /* the old one is now obsolete */
1821 if ( NULL != current_re_filterfile )
1823 current_re_filterfile->unloader = unload_re_filterfile;
1826 fs->next = files->next;
1828 current_re_filterfile = fs;
1837 load_re_filterfile_error:
1838 log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1839 csp->config->re_filterfile);
1843 #endif /* def PCRS */
1846 /*********************************************************************
1848 * Function : add_loader
1850 * Description : Called from `load_config'. Called once for each input
1851 * file found in config.
1854 * 1 : loader = pointer to a function that can parse and load
1855 * the appropriate config file.
1856 * 2 : config = The configuration_spec to add the loader to.
1860 *********************************************************************/
1861 void add_loader(int (*loader)(struct client_state *),
1862 struct configuration_spec * config)
1866 for (i=0; i < NLOADERS; i++)
1868 if (config->loaders[i] == NULL)
1870 config->loaders[i] = loader;
1878 /*********************************************************************
1880 * Function : run_loader
1882 * Description : Called from `load_config' and `listen_loop'. This
1883 * function keeps the "csp" current with any file mods
1884 * since the last loop. If a file is unchanged, the
1885 * loader functions do NOT reload the file.
1888 * 1 : csp = Current client state (buffers, headers, etc...)
1889 * Must be non-null. Reads: "csp->config"
1890 * Writes: various data members.
1892 * Returns : 0 => Ok, everything else is an error.
1894 *********************************************************************/
1895 int run_loader(struct client_state *csp)
1900 for (i=0; i < NLOADERS; i++)
1902 if (csp->config->loaders[i] == NULL)
1906 ret |= (csp->config->loaders[i])(csp);