1 const char loaders_rcs[] = "$Id: loaders.c,v 1.11 2001/05/29 23:25:24 oes Exp $";
2 /*********************************************************************
4 * File : $Source: /cvsroot/ijbswa/current/loaders.c,v $
6 * Purpose : Functions to load and unload the various
7 * configuration files. Also contains code to manage
8 * the list of active loaders, and to automatically
9 * unload files that are no longer in use.
11 * Copyright : Written by and Copyright (C) 2001 the SourceForge
12 * IJBSWA team. http://ijbswa.sourceforge.net
14 * Based on the Internet Junkbuster originally written
15 * by and Copyright (C) 1997 Anonymous Coders and
16 * Junkbusters Corporation. http://www.junkbusters.com
18 * This program is free software; you can redistribute it
19 * and/or modify it under the terms of the GNU General
20 * Public License as published by the Free Software
21 * Foundation; either version 2 of the License, or (at
22 * your option) any later version.
24 * This program is distributed in the hope that it will
25 * be useful, but WITHOUT ANY WARRANTY; without even the
26 * implied warranty of MERCHANTABILITY or FITNESS FOR A
27 * PARTICULAR PURPOSE. See the GNU General Public
28 * License for more details.
30 * The GNU General Public License should be included with
31 * this file. If not, you can view it at
32 * http://www.gnu.org/copyleft/gpl.html
33 * or write to the Free Software Foundation, Inc., 59
34 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
38 * Revision 1.11 2001/05/29 23:25:24 oes
40 * - load_config_line() and load_permissions_file() now use chomp()
42 * Revision 1.10 2001/05/29 09:50:24 jongfoster
43 * Unified blocklist/imagelist/permissionslist.
44 * File format is still under discussion, but the internal changes
47 * Also modified interceptor behaviour:
48 * - We now intercept all URLs beginning with one of the following
49 * prefixes (and *only* these prefixes):
51 * * http://ijbswa.sf.net/config/
52 * * http://ijbswa.sourceforge.net/config/
53 * - New interceptors "home page" - go to http://i.j.b/ to see it.
54 * - Internal changes so that intercepted and fast redirect pages
55 * are not replaced with an image.
56 * - Interceptors now have the option to send a binary page direct
57 * to the client. (i.e. ijb-send-banner uses this)
58 * - Implemented show-url-info interceptor. (Which is why I needed
59 * the above interceptors changes - a typical URL is
60 * "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
61 * The previous mechanism would not have intercepted that, and
62 * if it had been intercepted then it then it would have replaced
65 * Revision 1.9 2001/05/26 17:12:07 jongfoster
66 * Fatal errors loading configuration files now give better error messages.
68 * Revision 1.8 2001/05/26 00:55:20 jongfoster
69 * Removing duplicated code. load_forwardfile() now uses create_url_spec()
71 * Revision 1.7 2001/05/26 00:28:36 jongfoster
72 * Automatic reloading of config file.
73 * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
74 * Most of the global variables have been moved to a new
75 * struct configuration_spec, accessed through csp->config->globalname
76 * Most of the globals remaining are used by the Win32 GUI.
78 * Revision 1.6 2001/05/23 12:27:33 oes
80 * Fixed ugly indentation of my last changes
82 * Revision 1.5 2001/05/23 10:39:05 oes
83 * - Added support for escaping the comment character
84 * in config files by a backslash
85 * - Added support for line continuation in config
87 * - Fixed a buffer overflow bug with long config lines
89 * Revision 1.4 2001/05/22 18:56:28 oes
92 * Revision 1.3 2001/05/20 01:21:20 jongfoster
93 * Version 2.9.4 checkin.
94 * - Merged popupfile and cookiefile, and added control over PCRS
95 * filtering, in new "permissionsfile".
96 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
97 * file error you now get a message box (in the Win32 GUI) rather
98 * than the program exiting with no explanation.
99 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
101 * - Removed tabs from "config"
102 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
103 * - Bumped up version number.
105 * Revision 1.2 2001/05/17 23:01:01 oes
106 * - Cleaned CRLF's from the sources and related files
108 * Revision 1.1.1.1 2001/05/15 13:58:59 oes
109 * Initial import of version 2.9.3 source tree
112 *********************************************************************/
119 #include <sys/types.h>
123 #include <sys/stat.h>
137 #include "miscutil.h"
141 #ifndef SPLIT_PROXY_ARGS
143 #include "showargs.h"
144 #endif /* ndef SPLIT_PROXY_ARGS */
146 const char loaders_h_rcs[] = LOADERS_H_VERSION;
148 /* Fix a problem with Solaris. There should be no effect on other
150 * Solaris's isspace() is a macro which uses it's argument directly
151 * as an array index. Therefore we need to make sure that high-bit
152 * characters generate +ve values, and ideally we also want to make
153 * the argument match the declared parameter type of "int".
155 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
159 * Currently active files.
160 * These are also entered in the main linked list of files.
162 static struct file_list *current_permissions_file = NULL;
163 static struct file_list *current_forwardfile = NULL;
166 static struct file_list *current_aclfile = NULL;
167 #endif /* def ACL_FILES */
170 static struct file_list *current_trustfile = NULL;
171 #endif /* def TRUST_FILES */
174 static struct file_list *current_re_filterfile = NULL;
175 #endif /* def PCRS */
178 static int create_url_spec(struct url_spec * url, char * buf);
181 /*********************************************************************
185 * Description : Basically a mark and sweep garbage collector, it is run
186 * (by the parent thread) every once in a while to reclaim memory.
188 * It uses a mark and sweep strategy:
189 * 1) mark all files as inactive
191 * 2) check with each client:
192 * if it is active, mark its files as active
193 * if it is inactive, free its resources
195 * 3) free the resources of all of the files that
196 * are still marked as inactive (and are obsolete).
198 * N.B. files that are not obsolete don't have an unloader defined.
204 *********************************************************************/
207 struct file_list *fl, *nfl;
208 struct client_state *csp, *ncsp;
210 /* clear all of the file's active flags */
211 for ( fl = files->next; NULL != fl; fl = fl->next )
216 for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
220 /* mark this client's files as active */
223 * Always have a configuration file.
224 * (Also note the slightly non-standard extra
227 ncsp->config->config_file_list->active = 1;
229 if (ncsp->permissions_list) /* permissions files */
231 ncsp->permissions_list->active = 1;
234 if (ncsp->flist) /* forward files */
236 ncsp->flist->active = 1;
240 if (ncsp->alist) /* acl files */
242 ncsp->alist->active = 1;
244 #endif /* def ACL_FILES */
247 if (ncsp->rlist) /* perl re files */
249 ncsp->rlist->active = 1;
251 #endif /* def PCRS */
254 if (ncsp->tlist) /* trust files */
256 ncsp->tlist->active = 1;
258 #endif /* def TRUST_FILES */
263 /* this client one is not active, release its resources */
264 csp->next = ncsp->next;
266 freez(ncsp->ip_addr_str);
268 freez(ncsp->referrer);
269 #endif /* def TRUST_FILES */
270 freez(ncsp->x_forwarded);
271 freez(ncsp->iob->buf);
273 free_http_request(ncsp->http);
275 destroy_list(ncsp->headers);
276 destroy_list(ncsp->cookie_list);
284 #endif /* def STATISTICS */
290 for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
292 if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
294 fl->next = nfl->next;
296 (nfl->unloader)(nfl->f);
298 #ifndef SPLIT_PROXY_ARGS
299 freez(nfl->proxy_args);
300 #endif /* ndef SPLIT_PROXY_ARGS */
302 freez(nfl->filename);
311 /*********************************************************************
313 * Function : create_url_spec
315 * Description : Creates a "url_spec" structure from a string.
316 * When finished, free with unload_url().
319 * 1 : url = Target url_spec to be filled in. Must be
320 * zeroed out before the call (e.g. using zalloc).
321 * 2 : buf = Source pattern, null terminated. NOTE: The
322 * contents of this buffer are destroyed by this
323 * function. If this function succeeds, the
324 * buffer is copied to url->spec. If this
325 * function fails, the contents of the buffer
328 * Returns : 0 => Ok, everything else is an error.
330 *********************************************************************/
331 static int create_url_spec(struct url_spec * url, char * buf)
334 struct url_spec tmp_url[1];
336 /* paranoia - should never happen. */
337 if ((url == NULL) || (buf == NULL))
342 /* save a copy of the orignal specification */
343 if ((url->spec = strdup(buf)) == NULL)
348 if ((p = strchr(buf, '/')))
350 if (NULL == (url->path = strdup(p)))
355 url->pathlen = strlen(url->path);
369 if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
376 sprintf(rebuf, "^(%s)", url->path);
378 errcode = regcomp(url->preg, rebuf,
379 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
384 url->preg, buf, sizeof(buf));
388 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
399 if ((p = strchr(buf, ':')) == NULL)
409 if ((url->domain = strdup(buf)) == NULL)
415 #endif /* def REGEX */
419 /* split domain into components */
421 *tmp_url = dsplit(url->domain);
422 url->dbuf = tmp_url->dbuf;
423 url->dcnt = tmp_url->dcnt;
424 url->dvec = tmp_url->dvec;
425 url->unanchored = tmp_url->unanchored;
431 /*********************************************************************
433 * Function : unload_url
435 * Description : Called from the "unloaders". Freez the url
436 * structure elements.
439 * 1 : url = pointer to a url_spec structure.
443 *********************************************************************/
444 static void unload_url(struct url_spec *url)
446 if (url == NULL) return;
465 /*********************************************************************
467 * Function : unload_aclfile
469 * Description : Unloads an aclfile.
472 * 1 : f = the data structure associated with the aclfile.
476 *********************************************************************/
477 static void unload_aclfile(void *f)
479 struct access_control_list *b = (struct access_control_list *)f;
480 if (b == NULL) return;
482 unload_aclfile(b->next);
487 #endif /* def ACL_FILES */
490 /*********************************************************************
492 * Function : unload_permissions_file
494 * Description : Unloads a permissions file.
497 * 1 : file_data = the data structure associated with the
502 *********************************************************************/
503 static void unload_permissions_file(void *file_data)
505 struct permissions_spec * next;
506 struct permissions_spec * cur = (struct permissions_spec *)file_data;
510 unload_url(cur->url);
519 /*********************************************************************
521 * Function : unload_trustfile
523 * Description : Unloads a trustfile.
526 * 1 : f = the data structure associated with the trustfile.
530 *********************************************************************/
531 static void unload_trustfile(void *f)
533 struct block_spec *b = (struct block_spec *)f;
534 if (b == NULL) return;
536 unload_trustfile(b->next);
543 #endif /* def TRUST_FILES */
546 /*********************************************************************
548 * Function : unload_forwardfile
550 * Description : Unloads a forwardfile.
553 * 1 : f = the data structure associated with the forwardfile.
557 *********************************************************************/
558 static void unload_forwardfile(void *f)
560 struct forward_spec *b = (struct forward_spec *)f;
561 if (b == NULL) return;
563 unload_forwardfile(b->next);
567 freez(b->gw->gateway_host);
568 freez(b->gw->forward_host);
576 /*********************************************************************
578 * Function : unload_re_filterfile
580 * Description : Unload the re_filter list.
583 * 1 : f = the data structure associated with the filterfile.
587 *********************************************************************/
588 static void unload_re_filterfile(void *f)
591 struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
593 if (b == NULL) return;
595 destroy_list(b->patterns);
597 joblist = b->joblist;
598 while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
603 #endif /* def PCRS */
606 /*********************************************************************
608 * Function : check_file_changed
610 * Description : Helper function to check if a file needs reloading.
611 * If "current" is still current, return it. Otherwise
612 * allocates a new (zeroed) "struct file_list", fills
613 * in the disk file name and timestamp, and returns it.
616 * 1 : current = The file_list currently being used - will
617 * be checked to see if it is out of date.
618 * May be NULL (which is treated as out of
620 * 2 : filename = Name of file to check.
621 * 3 : newfl = New file list. [Output only]
622 * This will be set to NULL, OR a struct
623 * file_list newly allocated on the
624 * heap, with the filename and lastmodified
625 * fields filled, standard header giving file
626 * name in proxy_args, and all others zeroed.
627 * (proxy_args is only filled in if !defined
628 * SPLIT_PROXY_ARGS and !suppress_blocklists).
630 * Returns : If file unchanged: 0 (and sets newfl == NULL)
631 * If file changed: 1 and sets newfl != NULL
632 * On error: 1 and sets newfl == NULL
634 *********************************************************************/
635 int check_file_changed(const struct file_list * current,
636 const char * filename,
637 struct file_list ** newfl)
639 struct file_list *fs;
640 struct stat statbuf[1];
644 if (stat(filename, statbuf) < 0)
646 /* Error, probably file not found. */
651 && (current->lastmodified == statbuf->st_mtime)
652 && (0 == strcmp(current->filename, filename)))
657 fs = (struct file_list *)zalloc(sizeof(struct file_list));
661 /* Out of memory error */
665 fs->filename = strdup(filename);
666 fs->lastmodified = statbuf->st_mtime;
668 if (fs->filename == NULL)
670 /* Out of memory error */
675 #ifndef SPLIT_PROXY_ARGS
676 if (!suppress_blocklists)
678 char * p = html_encode(filename);
681 fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
682 fs->proxy_args = strsav(fs->proxy_args, p);
683 fs->proxy_args = strsav(fs->proxy_args,
684 "' contains the following patterns</h2>\n");
687 fs->proxy_args = strsav(fs->proxy_args, "<pre>");
689 #endif /* ndef SPLIT_PROXY_ARGS */
696 /*********************************************************************
698 * Function : read_config_line
700 * Description : Read a single non-empty line from a file and return
701 * it. Trims comments, leading and trailing whitespace
702 * and respects escaping of newline and comment char.
703 * Also writes the file to fs->proxy_args.
706 * 1 : buf = Buffer to use.
707 * 2 : buflen = Size of buffer in bytes.
708 * 3 : fp = File to read from
709 * 4 : fs = File will be written to fs->proxy_args. May
710 * be NULL to disable this feature.
712 * Returns : NULL on EOF or error
713 * Otherwise, returns buf.
715 *********************************************************************/
716 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
719 char linebuf[BUFSIZ];
724 while (fgets(linebuf, sizeof(linebuf), fp))
726 #ifndef SPLIT_PROXY_ARGS
727 if (fs && !suppress_blocklists)
729 char *html_line = html_encode(linebuf);
730 if (html_line != NULL)
732 fs->proxy_args = strsav(fs->proxy_args, html_line);
735 fs->proxy_args = strsav(fs->proxy_args, "<br>");
737 #endif /* ndef SPLIT_PROXY_ARGS */
739 /* Trim off newline */
740 if ((p = strpbrk(linebuf, "\r\n")) != NULL)
745 /* Line continuation? Trim escape and set flag. */
746 if ((p != linebuf) && (*--p == '\\'))
752 /* If there's a comment char.. */
753 if ((p = strpbrk(linebuf, "#")) != NULL)
755 /* ..and it's escaped, left-shift the line over the escape. */
756 if ((p != linebuf) && (*(p-1) == '\\'))
759 while ((*q++ = *p++) != '\0') /* nop */;
761 /* Else, chop off the rest of the line */
768 /* Remove leading and trailing whitespace */
773 strncat(buf, linebuf, buflen - strlen(buf));
792 /*********************************************************************
794 * Function : load_aclfile
796 * Description : Read and parse an aclfile and add to files list.
799 * 1 : csp = Current client state (buffers, headers, etc...)
801 * Returns : 0 => Ok, everything else is an error.
803 *********************************************************************/
804 int load_aclfile(struct client_state *csp)
807 char buf[BUFSIZ], *v[3], *p;
809 struct access_control_list *a, *bl;
810 struct file_list *fs;
812 if (!check_file_changed(current_aclfile, csp->config->aclfile, &fs))
814 /* No need to load */
817 csp->alist = current_aclfile;
823 goto load_aclfile_error;
826 fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
831 goto load_aclfile_error;
834 fp = fopen(csp->config->aclfile, "r");
838 goto load_aclfile_error;
841 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
843 i = ssplit(buf, " \t", v, SZ(v), 1, 1);
845 /* allocate a new node */
846 a = (struct access_control_list *) zalloc(sizeof(*a));
854 goto load_aclfile_error;
857 /* add it to the list */
864 if (acl_addr(v[2], a->dst) < 0)
866 goto load_aclfile_error;
871 if (acl_addr(v[1], a->src) < 0)
873 goto load_aclfile_error;
877 if (strcmpic(p, "permit") == 0)
879 a->action = ACL_PERMIT;
883 if (strcmpic(p, "deny") == 0)
885 a->action = ACL_DENY;
891 goto load_aclfile_error;
897 #ifndef SPLIT_PROXY_ARGS
898 if (!suppress_blocklists)
900 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
902 #endif /* ndef SPLIT_PROXY_ARGS */
906 current_aclfile->unloader = unload_aclfile;
909 fs->next = files->next;
911 current_aclfile = fs;
921 log_error(LOG_LEVEL_FATAL, "can't load access control list %s: %E",
922 csp->config->aclfile);
926 #endif /* def ACL_FILES */
929 struct permission_alias
932 unsigned mask; /* a bit set to "0" = remove permission */
933 unsigned add; /* a bit set to "1" = add permission */
934 struct permission_alias * next;
939 * Note: this is special-cased in the code so we don't need to
940 * fill in the ->next fields.
942 static const struct permission_alias standard_aliases[] =
944 { "+block", PERMIT_MASK_ALL, PERMIT_BLOCK },
945 /* { "+cookies", PERMIT_MASK_ALL, PERMIT_COOKIE_SET | PERMIT_COOKIE_READ }, */
946 { "+cookies-read", PERMIT_MASK_ALL, PERMIT_COOKIE_READ },
947 { "+cookies-set", PERMIT_MASK_ALL, PERMIT_COOKIE_SET },
948 { "+fast-redirects", PERMIT_MASK_ALL, PERMIT_FAST_REDIRECTS },
949 { "+filter", PERMIT_MASK_ALL, PERMIT_RE_FILTER },
950 { "+image", PERMIT_MASK_ALL, PERMIT_IMAGE },
951 { "+popup", PERMIT_MASK_ALL, PERMIT_POPUPS },
952 { "+popups", PERMIT_MASK_ALL, PERMIT_POPUPS },
953 { "+referer", PERMIT_MASK_ALL, PERMIT_REFERER },
954 { "+referrer", PERMIT_MASK_ALL, PERMIT_REFERER },
955 { "-block", ~PERMIT_BLOCK, 0 },
956 /* { "-cookies", ~(PERMIT_COOKIE_SET | PERMIT_COOKIE_READ), 0 }, */
957 { "-cookies-read", ~PERMIT_COOKIE_READ, 0 },
958 { "-cookies-set", ~PERMIT_COOKIE_SET, 0 },
959 { "-fast-redirects", ~PERMIT_FAST_REDIRECTS, 0 },
960 { "-filter", ~PERMIT_RE_FILTER, 0 },
961 { "-image", ~PERMIT_IMAGE, 0 },
962 { "-popup", ~PERMIT_POPUPS, 0 },
963 { "-popups", ~PERMIT_POPUPS, 0 },
964 { "-referer", ~PERMIT_REFERER, 0 },
965 { "-referrer", ~PERMIT_REFERER, 0 },
966 { NULL, 0, 0 } /* End marker */
970 /*********************************************************************
972 * Function : load_permissions_file
974 * Description : Read and parse a permissions file and add to files
978 * 1 : csp = Current client state (buffers, headers, etc...)
980 * Returns : 0 => Ok, everything else is an error.
982 *********************************************************************/
983 int load_permissions_file(struct client_state *csp)
987 struct permissions_spec *last_perm;
988 struct permissions_spec *perm;
990 struct file_list *fs;
991 #define MODE_START_OF_FILE 1
992 #define MODE_PERMISSIONS 2
994 int mode = MODE_START_OF_FILE;
995 unsigned curmask = PERMIT_MASK_ALL;
997 struct permission_alias * alias_list = NULL;
999 if (!check_file_changed(current_permissions_file, csp->config->permissions_file, &fs))
1001 /* No need to load */
1004 csp->permissions_list = current_permissions_file;
1010 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': error finding file: %E",
1011 csp->config->permissions_file);
1012 return 1; /* never get here */
1015 fs->f = last_perm = (struct permissions_spec *)zalloc(sizeof(*last_perm));
1016 if (last_perm == NULL)
1018 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': out of memory!",
1019 csp->config->permissions_file);
1020 return 1; /* never get here */
1023 if ((fp = fopen(csp->config->permissions_file, "r")) == NULL)
1025 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': error opening file: %E",
1026 csp->config->permissions_file);
1027 return 1; /* never get here */
1030 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1034 /* It's a header block */
1037 /* It's {{settings}} or {{alias}} */
1038 int len = strlen(buf);
1039 char * start = buf + 2;
1040 char * end = buf + len - 1;
1041 if ((len < 5) || (*end-- != '}') || (*end-- != '}'))
1045 log_error(LOG_LEVEL_FATAL,
1046 "can't load permissions file '%s': invalid line: %s",
1047 csp->config->permissions_file, buf);
1048 return 1; /* never get here */
1051 /* Trim leading and trailing whitespace. */
1059 log_error(LOG_LEVEL_FATAL,
1060 "can't load permissions file '%s': invalid line: {{ }}",
1061 csp->config->permissions_file);
1062 return 1; /* never get here */
1065 if (0 == strcmpic(start, "alias"))
1067 /* it's an {{alias}} block */
1073 /* invalid {{something}} block */
1075 log_error(LOG_LEVEL_FATAL,
1076 "can't load permissions file '%s': invalid line: {{%s}}",
1077 csp->config->permissions_file, start);
1078 return 1; /* never get here */
1083 /* It's a permissions block */
1087 int len = strlen(buf);
1088 char * start = buf + 1;
1089 char * end = buf + len - 1;
1091 if ((len < 3) || (*end-- != '}'))
1095 log_error(LOG_LEVEL_FATAL,
1096 "can't load permissions file '%s': invalid line: %s",
1097 csp->config->permissions_file, buf);
1098 return 1; /* never get here */
1108 log_error(LOG_LEVEL_FATAL,
1109 "can't load permissions file '%s': invalid line: { }",
1110 csp->config->permissions_file);
1111 return 1; /* never get here */
1114 mode = MODE_PERMISSIONS;
1116 curmask = PERMIT_MASK_ALL;
1121 const struct permission_alias * alias = standard_aliases;
1122 char * option = start;
1123 while ((*start != '\0') && (*start != ' ') && (*start != '\t'))
1128 more = (*start != 0);
1133 /* Eat all the whitespace between the options */
1134 while ((*start == ' ') || (*start == '\t'))
1140 /* handle option in 'option' */
1142 /* Check for standard permission name */
1143 while ( (alias->name != NULL) && (0 != strcmpic(alias->name, option)) )
1147 if (alias->name == NULL)
1149 /* try user aliases. */
1151 while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) )
1153 alias = alias->next;
1158 /* Bad permission name */
1160 log_error(LOG_LEVEL_FATAL,
1161 "can't load permissions file '%s': invalid permission name: %s",
1162 csp->config->permissions_file, option);
1163 return 1; /* never get here */
1165 curmask &= alias->mask;
1166 curadd &= alias->mask;
1167 curadd |= alias->add;
1171 else if (mode == MODE_ALIAS)
1173 /* define an alias */
1174 struct permission_alias * new_alias;
1177 char * start = strchr(buf, '=');
1180 if ((start == NULL) || (start == buf))
1182 log_error(LOG_LEVEL_FATAL,
1183 "can't load permissions file '%s': invalid alias line: %s",
1184 csp->config->permissions_file, buf);
1185 return 1; /* never get here */
1188 if ((new_alias = zalloc(sizeof(*new_alias))) == NULL)
1191 log_error(LOG_LEVEL_FATAL,
1192 "can't load permissions file '%s': out of memory!",
1193 csp->config->permissions_file);
1194 return 1; /* never get here */
1197 /* Eat any the whitespace after the '=' */
1199 while ((*start == ' ') || (*start == '\t'))
1205 log_error(LOG_LEVEL_FATAL,
1206 "can't load permissions file '%s': invalid alias line: %s",
1207 csp->config->permissions_file, buf);
1208 return 1; /* never get here */
1211 /* Eat any the whitespace before the '=' */
1213 while ((*end == ' ') || (*end == '\t'))
1216 * we already know we must have at least 1 non-ws char
1217 * at start of buf - no need to check
1223 new_alias->name = strdup(buf);
1225 curmask = PERMIT_MASK_ALL;
1230 const struct permission_alias * alias = standard_aliases;
1231 char * option = start;
1232 while ((*start != '\0') && (*start != ' ') && (*start != '\t'))
1237 more = (*start != 0);
1242 /* Eat all the whitespace between the options */
1243 while ((*start == ' ') || (*start == '\t'))
1249 /* handle option in 'option' */
1251 /* Check for standard permission name */
1252 while ( (alias->name != NULL) && (0 != strcmpic(alias->name, option)) )
1256 if (alias->name == NULL)
1258 /* try user aliases. */
1260 while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) )
1262 alias = alias->next;
1267 /* Bad permission name */
1269 log_error(LOG_LEVEL_FATAL,
1270 "can't load permissions file '%s': invalid permission name: %s",
1271 csp->config->permissions_file, option);
1272 return 1; /* never get here */
1274 curmask &= alias->mask;
1275 curadd &= alias->mask;
1276 curadd |= alias->add;
1279 /* save alias permissions */
1280 new_alias->mask = curmask;
1281 new_alias->add = curadd;
1284 new_alias->next = alias_list;
1285 alias_list = new_alias;
1287 else if (mode == MODE_PERMISSIONS)
1289 /* it's a URL pattern */
1291 /* allocate a new node */
1292 if ((perm = zalloc(sizeof(*perm))) == NULL)
1295 log_error(LOG_LEVEL_FATAL,
1296 "can't load permissions file '%s': out of memory!",
1297 csp->config->permissions_file);
1298 return 1; /* never get here */
1302 perm->mask = curmask;
1305 /* Save the URL pattern */
1306 if (create_url_spec(perm->url, buf))
1309 log_error(LOG_LEVEL_FATAL,
1310 "can't load permissions file '%s': cannot create URL permission from: %s",
1311 csp->config->permissions_file, buf);
1312 return 1; /* never get here */
1315 /* add it to the list */
1316 last_perm->next = perm;
1319 else if (mode == MODE_START_OF_FILE)
1321 /* oops - please have a {} line as 1st line in file. */
1323 log_error(LOG_LEVEL_FATAL,
1324 "can't load permissions file '%s': first line is invalid: %s",
1325 csp->config->permissions_file, buf);
1326 return 1; /* never get here */
1330 /* How did we get here? This is impossible! */
1332 log_error(LOG_LEVEL_FATAL,
1333 "can't load permissions file '%s': INTERNAL ERROR - mode = %d",
1334 csp->config->permissions_file, mode);
1335 return 1; /* never get here */
1341 while (alias_list != NULL)
1343 struct permission_alias * next = alias_list->next;
1344 freez((char *)alias_list->name);
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;
1377 /*********************************************************************
1379 * Function : load_trustfile
1381 * Description : Read and parse a trustfile and add to files list.
1384 * 1 : csp = Current client state (buffers, headers, etc...)
1386 * Returns : 0 => Ok, everything else is an error.
1388 *********************************************************************/
1389 int load_trustfile(struct client_state *csp)
1393 struct block_spec *b, *bl;
1394 struct url_spec **tl;
1396 char buf[BUFSIZ], *p, *q;
1397 int reject, trusted;
1398 struct file_list *fs;
1400 if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
1402 /* No need to load */
1405 csp->tlist = current_trustfile;
1411 goto load_trustfile_error;
1414 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1417 goto load_trustfile_error;
1420 if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
1422 goto load_trustfile_error;
1425 tl = csp->config->trust_list;
1427 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1443 while ((*p++ = *q++))
1449 /* skip blank lines */
1455 /* allocate a new node */
1456 if ((b = zalloc(sizeof(*b))) == NULL)
1459 goto load_trustfile_error;
1462 /* add it to the list */
1468 /* Save the URL pattern */
1469 if (create_url_spec(b->url, buf))
1472 goto load_trustfile_error;
1476 * save a pointer to URL's spec in the list of trusted URL's, too
1488 #ifndef SPLIT_PROXY_ARGS
1489 if (!suppress_blocklists)
1491 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1493 #endif /* ndef SPLIT_PROXY_ARGS */
1495 /* the old one is now obsolete */
1496 if (current_trustfile)
1498 current_trustfile->unloader = unload_trustfile;
1501 fs->next = files->next;
1503 current_trustfile = fs;
1512 load_trustfile_error:
1513 log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1514 csp->config->trustfile);
1518 #endif /* def TRUST_FILES */
1521 /*********************************************************************
1523 * Function : load_forwardfile
1525 * Description : Read and parse a forwardfile and add to files list.
1528 * 1 : csp = Current client state (buffers, headers, etc...)
1530 * Returns : 0 => Ok, everything else is an error.
1532 *********************************************************************/
1533 int load_forwardfile(struct client_state *csp)
1537 struct forward_spec *b, *bl;
1542 struct file_list *fs;
1543 const struct gateway *gw;
1545 if (!check_file_changed(current_forwardfile, csp->config->forwardfile, &fs))
1547 /* No need to load */
1550 csp->flist = current_forwardfile;
1556 goto load_forwardfile_error;
1559 fs->f = bl = (struct forward_spec *)zalloc(sizeof(*bl));
1561 if ((fs == NULL) || (bl == NULL))
1563 goto load_forwardfile_error;
1566 if ((fp = fopen(csp->config->forwardfile, "r")) == NULL)
1568 goto load_forwardfile_error;
1573 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1579 n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1583 log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1587 strcpy(buf, vec[0]);
1589 /* skip lines containing only ~ */
1595 /* allocate a new node */
1596 if (((b = zalloc(sizeof(*b))) == NULL)
1600 goto load_forwardfile_error;
1603 /* add it to the list */
1607 /* Save the URL pattern */
1608 if (create_url_spec(b->url, buf))
1611 goto load_forwardfile_error;
1614 /* now parse the gateway specs */
1618 for (gw = gateways; gw->name; gw++)
1620 if (strcmp(gw->name, p) == 0)
1626 if (gw->name == NULL)
1628 goto load_forwardfile_error;
1631 /* save this as the gateway type */
1634 /* now parse the gateway host[:port] spec */
1637 if (strcmp(p, ".") != 0)
1639 b->gw->gateway_host = strdup(p);
1641 if ((p = strchr(b->gw->gateway_host, ':')))
1644 b->gw->gateway_port = atoi(p);
1647 if (b->gw->gateway_port <= 0)
1649 goto load_forwardfile_error;
1653 /* now parse the forwarding spec */
1656 if (strcmp(p, ".") != 0)
1658 b->gw->forward_host = strdup(p);
1660 if ((p = strchr(b->gw->forward_host, ':')))
1663 b->gw->forward_port = atoi(p);
1666 if (b->gw->forward_port <= 0)
1668 b->gw->forward_port = 8000;
1677 #ifndef SPLIT_PROXY_ARGS
1678 if (!suppress_blocklists)
1680 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1682 #endif /* ndef SPLIT_PROXY_ARGS */
1684 /* the old one is now obsolete */
1685 if (current_forwardfile)
1687 current_forwardfile->unloader = unload_forwardfile;
1690 fs->next = files->next;
1692 current_forwardfile = fs;
1701 load_forwardfile_error:
1702 log_error(LOG_LEVEL_FATAL, "can't load forwardfile '%s': %E",
1703 csp->config->forwardfile);
1710 /*********************************************************************
1712 * Function : load_re_filterfile
1714 * Description : Load the re_filterfile. Each non-comment, non-empty
1715 * line is instantly added to the joblist, which is
1716 * a chained list of pcrs_job structs.
1719 * 1 : csp = Current client state (buffers, headers, etc...)
1721 * Returns : 0 => Ok, everything else is an error.
1723 *********************************************************************/
1724 int load_re_filterfile(struct client_state *csp)
1728 struct re_filterfile_spec *bl;
1729 struct file_list *fs;
1735 if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1737 /* No need to load */
1740 csp->rlist = current_re_filterfile;
1746 goto load_re_filterfile_error;
1749 fs->f = bl = (struct re_filterfile_spec *)zalloc(sizeof(*bl));
1752 goto load_re_filterfile_error;
1755 /* Open the file or fail */
1756 if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1758 goto load_re_filterfile_error;
1761 /* Read line by line */
1762 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1764 enlist( bl->patterns, buf );
1766 /* We have a meaningful line -> make it a job */
1767 if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1769 log_error(LOG_LEVEL_RE_FILTER,
1770 "Adding re_filter job %s failed with error %d.", buf, error);
1775 dummy->next = bl->joblist;
1776 bl->joblist = dummy;
1777 log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1783 #ifndef SPLIT_PROXY_ARGS
1784 if (!suppress_blocklists)
1786 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1788 #endif /* ndef SPLIT_PROXY_ARGS */
1790 /* the old one is now obsolete */
1791 if ( NULL != current_re_filterfile )
1793 current_re_filterfile->unloader = unload_re_filterfile;
1796 fs->next = files->next;
1798 current_re_filterfile = fs;
1807 load_re_filterfile_error:
1808 log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1809 csp->config->re_filterfile);
1813 #endif /* def PCRS */
1816 /*********************************************************************
1818 * Function : add_loader
1820 * Description : Called from `load_config'. Called once for each input
1821 * file found in config.
1824 * 1 : loader = pointer to a function that can parse and load
1825 * the appropriate config file.
1826 * 2 : config = The configuration_spec to add the loader to.
1830 *********************************************************************/
1831 void add_loader(int (*loader)(struct client_state *),
1832 struct configuration_spec * config)
1836 for (i=0; i < NLOADERS; i++)
1838 if (config->loaders[i] == NULL)
1840 config->loaders[i] = loader;
1848 /*********************************************************************
1850 * Function : run_loader
1852 * Description : Called from `load_config' and `listen_loop'. This
1853 * function keeps the "csp" current with any file mods
1854 * since the last loop. If a file is unchanged, the
1855 * loader functions do NOT reload the file.
1858 * 1 : csp = Current client state (buffers, headers, etc...)
1859 * Must be non-null. Reads: "csp->config"
1860 * Writes: various data members.
1862 * Returns : 0 => Ok, everything else is an error.
1864 *********************************************************************/
1865 int run_loader(struct client_state *csp)
1870 for (i=0; i < NLOADERS; i++)
1872 if (csp->config->loaders[i] == NULL)
1876 ret |= (csp->config->loaders[i])(csp);