1 const char loaders_rcs[] = "$Id: loaders.c,v 1.10 2001/05/29 09:50:24 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.10 2001/05/29 09:50:24 jongfoster
39 * Unified blocklist/imagelist/permissionslist.
40 * File format is still under discussion, but the internal changes
43 * Also modified interceptor behaviour:
44 * - We now intercept all URLs beginning with one of the following
45 * prefixes (and *only* these prefixes):
47 * * http://ijbswa.sf.net/config/
48 * * http://ijbswa.sourceforge.net/config/
49 * - New interceptors "home page" - go to http://i.j.b/ to see it.
50 * - Internal changes so that intercepted and fast redirect pages
51 * are not replaced with an image.
52 * - Interceptors now have the option to send a binary page direct
53 * to the client. (i.e. ijb-send-banner uses this)
54 * - Implemented show-url-info interceptor. (Which is why I needed
55 * the above interceptors changes - a typical URL is
56 * "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
57 * The previous mechanism would not have intercepted that, and
58 * if it had been intercepted then it then it would have replaced
61 * Revision 1.9 2001/05/26 17:12:07 jongfoster
62 * Fatal errors loading configuration files now give better error messages.
64 * Revision 1.8 2001/05/26 00:55:20 jongfoster
65 * Removing duplicated code. load_forwardfile() now uses create_url_spec()
67 * Revision 1.7 2001/05/26 00:28:36 jongfoster
68 * Automatic reloading of config file.
69 * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
70 * Most of the global variables have been moved to a new
71 * struct configuration_spec, accessed through csp->config->globalname
72 * Most of the globals remaining are used by the Win32 GUI.
74 * Revision 1.6 2001/05/23 12:27:33 oes
76 * Fixed ugly indentation of my last changes
78 * Revision 1.5 2001/05/23 10:39:05 oes
79 * - Added support for escaping the comment character
80 * in config files by a backslash
81 * - Added support for line continuation in config
83 * - Fixed a buffer overflow bug with long config lines
85 * Revision 1.4 2001/05/22 18:56:28 oes
88 * Revision 1.3 2001/05/20 01:21:20 jongfoster
89 * Version 2.9.4 checkin.
90 * - Merged popupfile and cookiefile, and added control over PCRS
91 * filtering, in new "permissionsfile".
92 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
93 * file error you now get a message box (in the Win32 GUI) rather
94 * than the program exiting with no explanation.
95 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
97 * - Removed tabs from "config"
98 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
99 * - Bumped up version number.
101 * Revision 1.2 2001/05/17 23:01:01 oes
102 * - Cleaned CRLF's from the sources and related files
104 * Revision 1.1.1.1 2001/05/15 13:58:59 oes
105 * Initial import of version 2.9.3 source tree
108 *********************************************************************/
115 #include <sys/types.h>
119 #include <sys/stat.h>
133 #include "miscutil.h"
137 #ifndef SPLIT_PROXY_ARGS
139 #include "showargs.h"
140 #endif /* ndef SPLIT_PROXY_ARGS */
142 const char loaders_h_rcs[] = LOADERS_H_VERSION;
144 /* Fix a problem with Solaris. There should be no effect on other
146 * Solaris's isspace() is a macro which uses it's argument directly
147 * as an array index. Therefore we need to make sure that high-bit
148 * characters generate +ve values, and ideally we also want to make
149 * the argument match the declared parameter type of "int".
151 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
155 * Currently active files.
156 * These are also entered in the main linked list of files.
158 static struct file_list *current_permissions_file = NULL;
159 static struct file_list *current_forwardfile = NULL;
162 static struct file_list *current_aclfile = NULL;
163 #endif /* def ACL_FILES */
166 static struct file_list *current_trustfile = NULL;
167 #endif /* def TRUST_FILES */
170 static struct file_list *current_re_filterfile = NULL;
171 #endif /* def PCRS */
174 static int create_url_spec(struct url_spec * url, char * buf);
177 /*********************************************************************
181 * Description : Basically a mark and sweep garbage collector, it is run
182 * (by the parent thread) every once in a while to reclaim memory.
184 * It uses a mark and sweep strategy:
185 * 1) mark all files as inactive
187 * 2) check with each client:
188 * if it is active, mark its files as active
189 * if it is inactive, free its resources
191 * 3) free the resources of all of the files that
192 * are still marked as inactive (and are obsolete).
194 * N.B. files that are not obsolete don't have an unloader defined.
200 *********************************************************************/
203 struct file_list *fl, *nfl;
204 struct client_state *csp, *ncsp;
206 /* clear all of the file's active flags */
207 for ( fl = files->next; NULL != fl; fl = fl->next )
212 for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
216 /* mark this client's files as active */
219 * Always have a configuration file.
220 * (Also note the slightly non-standard extra
223 ncsp->config->config_file_list->active = 1;
225 if (ncsp->permissions_list) /* permissions files */
227 ncsp->permissions_list->active = 1;
230 if (ncsp->flist) /* forward files */
232 ncsp->flist->active = 1;
236 if (ncsp->alist) /* acl files */
238 ncsp->alist->active = 1;
240 #endif /* def ACL_FILES */
243 if (ncsp->rlist) /* perl re files */
245 ncsp->rlist->active = 1;
247 #endif /* def PCRS */
250 if (ncsp->tlist) /* trust files */
252 ncsp->tlist->active = 1;
254 #endif /* def TRUST_FILES */
259 /* this client one is not active, release its resources */
260 csp->next = ncsp->next;
262 freez(ncsp->ip_addr_str);
264 freez(ncsp->referrer);
265 #endif /* def TRUST_FILES */
266 freez(ncsp->x_forwarded);
267 freez(ncsp->iob->buf);
269 free_http_request(ncsp->http);
271 destroy_list(ncsp->headers);
272 destroy_list(ncsp->cookie_list);
280 #endif /* def STATISTICS */
286 for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
288 if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
290 fl->next = nfl->next;
292 (nfl->unloader)(nfl->f);
294 #ifndef SPLIT_PROXY_ARGS
295 freez(nfl->proxy_args);
296 #endif /* ndef SPLIT_PROXY_ARGS */
298 freez(nfl->filename);
307 /*********************************************************************
309 * Function : create_url_spec
311 * Description : Creates a "url_spec" structure from a string.
312 * When finished, free with unload_url().
315 * 1 : url = Target url_spec to be filled in. Must be
316 * zeroed out before the call (e.g. using zalloc).
317 * 2 : buf = Source pattern, null terminated. NOTE: The
318 * contents of this buffer are destroyed by this
319 * function. If this function succeeds, the
320 * buffer is copied to url->spec. If this
321 * function fails, the contents of the buffer
324 * Returns : 0 => Ok, everything else is an error.
326 *********************************************************************/
327 static int create_url_spec(struct url_spec * url, char * buf)
330 struct url_spec tmp_url[1];
332 /* paranoia - should never happen. */
333 if ((url == NULL) || (buf == NULL))
338 /* save a copy of the orignal specification */
339 if ((url->spec = strdup(buf)) == NULL)
344 if ((p = strchr(buf, '/')))
346 if (NULL == (url->path = strdup(p)))
351 url->pathlen = strlen(url->path);
365 if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
372 sprintf(rebuf, "^(%s)", url->path);
374 errcode = regcomp(url->preg, rebuf,
375 (REG_EXTENDED|REG_NOSUB|REG_ICASE));
380 url->preg, buf, sizeof(buf));
384 log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
395 if ((p = strchr(buf, ':')) == NULL)
405 if ((url->domain = strdup(buf)) == NULL)
411 #endif /* def REGEX */
415 /* split domain into components */
417 *tmp_url = dsplit(url->domain);
418 url->dbuf = tmp_url->dbuf;
419 url->dcnt = tmp_url->dcnt;
420 url->dvec = tmp_url->dvec;
426 /*********************************************************************
428 * Function : unload_url
430 * Description : Called from the "unloaders". Freez the url
431 * structure elements.
434 * 1 : url = pointer to a url_spec structure.
438 *********************************************************************/
439 static void unload_url(struct url_spec *url)
441 if (url == NULL) return;
460 /*********************************************************************
462 * Function : unload_aclfile
464 * Description : Unloads an aclfile.
467 * 1 : f = the data structure associated with the aclfile.
471 *********************************************************************/
472 static void unload_aclfile(void *f)
474 struct access_control_list *b = (struct access_control_list *)f;
475 if (b == NULL) return;
477 unload_aclfile(b->next);
482 #endif /* def ACL_FILES */
485 /*********************************************************************
487 * Function : unload_permissions_file
489 * Description : Unloads a permissions file.
492 * 1 : file_data = the data structure associated with the
497 *********************************************************************/
498 static void unload_permissions_file(void *file_data)
500 struct permissions_spec * next;
501 struct permissions_spec * cur = (struct permissions_spec *)file_data;
505 unload_url(cur->url);
514 /*********************************************************************
516 * Function : unload_trustfile
518 * Description : Unloads a trustfile.
521 * 1 : f = the data structure associated with the trustfile.
525 *********************************************************************/
526 static void unload_trustfile(void *f)
528 struct block_spec *b = (struct block_spec *)f;
529 if (b == NULL) return;
531 unload_trustfile(b->next);
538 #endif /* def TRUST_FILES */
541 /*********************************************************************
543 * Function : unload_forwardfile
545 * Description : Unloads a forwardfile.
548 * 1 : f = the data structure associated with the forwardfile.
552 *********************************************************************/
553 static void unload_forwardfile(void *f)
555 struct forward_spec *b = (struct forward_spec *)f;
556 if (b == NULL) return;
558 unload_forwardfile(b->next);
562 freez(b->gw->gateway_host);
563 freez(b->gw->forward_host);
571 /*********************************************************************
573 * Function : unload_re_filterfile
575 * Description : Unload the re_filter list.
578 * 1 : f = the data structure associated with the filterfile.
582 *********************************************************************/
583 static void unload_re_filterfile(void *f)
586 struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
588 if (b == NULL) return;
590 destroy_list(b->patterns);
592 joblist = b->joblist;
593 while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
598 #endif /* def PCRS */
601 /*********************************************************************
603 * Function : check_file_changed
605 * Description : Helper function to check if a file needs reloading.
606 * If "current" is still current, return it. Otherwise
607 * allocates a new (zeroed) "struct file_list", fills
608 * in the disk file name and timestamp, and returns it.
611 * 1 : current = The file_list currently being used - will
612 * be checked to see if it is out of date.
613 * May be NULL (which is treated as out of
615 * 2 : filename = Name of file to check.
616 * 3 : newfl = New file list. [Output only]
617 * This will be set to NULL, OR a struct
618 * file_list newly allocated on the
619 * heap, with the filename and lastmodified
620 * fields filled, standard header giving file
621 * name in proxy_args, and all others zeroed.
622 * (proxy_args is only filled in if !defined
623 * SPLIT_PROXY_ARGS and !suppress_blocklists).
625 * Returns : If file unchanged: 0 (and sets newfl == NULL)
626 * If file changed: 1 and sets newfl != NULL
627 * On error: 1 and sets newfl == NULL
629 *********************************************************************/
630 int check_file_changed(const struct file_list * current,
631 const char * filename,
632 struct file_list ** newfl)
634 struct file_list *fs;
635 struct stat statbuf[1];
639 if (stat(filename, statbuf) < 0)
641 /* Error, probably file not found. */
646 && (current->lastmodified == statbuf->st_mtime)
647 && (0 == strcmp(current->filename, filename)))
652 fs = (struct file_list *)zalloc(sizeof(struct file_list));
656 /* Out of memory error */
660 fs->filename = strdup(filename);
661 fs->lastmodified = statbuf->st_mtime;
663 if (fs->filename == NULL)
665 /* Out of memory error */
670 #ifndef SPLIT_PROXY_ARGS
671 if (!suppress_blocklists)
673 char * p = html_encode(filename);
676 fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
677 fs->proxy_args = strsav(fs->proxy_args, p);
678 fs->proxy_args = strsav(fs->proxy_args,
679 "' contains the following patterns</h2>\n");
682 fs->proxy_args = strsav(fs->proxy_args, "<pre>");
684 #endif /* ndef SPLIT_PROXY_ARGS */
691 /*********************************************************************
693 * Function : read_config_line
695 * Description : Read a single non-empty line from a file and return
696 * it. Trims comments, leading and trailing whitespace
697 * and respects escaping of newline and comment char.
698 * Also writes the file to fs->proxy_args.
701 * 1 : buf = Buffer to use.
702 * 2 : buflen = Size of buffer in bytes.
703 * 3 : fp = File to read from
704 * 4 : fs = File will be written to fs->proxy_args. May
705 * be NULL to disable this feature.
707 * Returns : NULL on EOF or error
708 * Otherwise, returns buf.
710 *********************************************************************/
711 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
714 char linebuf[BUFSIZ];
719 while (fgets(linebuf, sizeof(linebuf), fp))
721 #ifndef SPLIT_PROXY_ARGS
722 if (fs && !suppress_blocklists)
724 char *html_line = html_encode(linebuf);
725 if (html_line != NULL)
727 fs->proxy_args = strsav(fs->proxy_args, html_line);
730 fs->proxy_args = strsav(fs->proxy_args, "<br>");
732 #endif /* ndef SPLIT_PROXY_ARGS */
734 /* Trim off newline */
735 if ((p = strpbrk(linebuf, "\r\n")) != NULL)
740 /* Line continuation? Trim escape and set flag. */
741 if ((p != linebuf) && (*--p == '\\'))
747 /* If there's a comment char.. */
748 if ((p = strpbrk(linebuf, "#")) != NULL)
750 /* ..and it's escaped, left-shift the line over the escape. */
751 if ((p != linebuf) && (*(p-1) == '\\'))
754 while ((*q++ = *p++) != '\0') /* nop */;
756 /* Else, chop off the rest of the line */
763 /* Remove leading and trailing whitespace */
768 strncat(buf, linebuf, buflen - strlen(buf));
787 /*********************************************************************
789 * Function : load_aclfile
791 * Description : Read and parse an aclfile and add to files list.
794 * 1 : csp = Current client state (buffers, headers, etc...)
796 * Returns : 0 => Ok, everything else is an error.
798 *********************************************************************/
799 int load_aclfile(struct client_state *csp)
802 char buf[BUFSIZ], *v[3], *p;
804 struct access_control_list *a, *bl;
805 struct file_list *fs;
807 if (!check_file_changed(current_aclfile, csp->config->aclfile, &fs))
809 /* No need to load */
812 csp->alist = current_aclfile;
818 goto load_aclfile_error;
821 fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
826 goto load_aclfile_error;
829 fp = fopen(csp->config->aclfile, "r");
833 goto load_aclfile_error;
836 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
838 i = ssplit(buf, " \t", v, SZ(v), 1, 1);
840 /* allocate a new node */
841 a = (struct access_control_list *) zalloc(sizeof(*a));
849 goto load_aclfile_error;
852 /* add it to the list */
859 if (acl_addr(v[2], a->dst) < 0)
861 goto load_aclfile_error;
866 if (acl_addr(v[1], a->src) < 0)
868 goto load_aclfile_error;
872 if (strcmpic(p, "permit") == 0)
874 a->action = ACL_PERMIT;
878 if (strcmpic(p, "deny") == 0)
880 a->action = ACL_DENY;
886 goto load_aclfile_error;
892 #ifndef SPLIT_PROXY_ARGS
893 if (!suppress_blocklists)
895 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
897 #endif /* ndef SPLIT_PROXY_ARGS */
901 current_aclfile->unloader = unload_aclfile;
904 fs->next = files->next;
906 current_aclfile = fs;
916 log_error(LOG_LEVEL_FATAL, "can't load access control list %s: %E",
917 csp->config->aclfile);
921 #endif /* def ACL_FILES */
924 struct permission_alias
927 unsigned mask; /* a bit set to "0" = remove permission */
928 unsigned add; /* a bit set to "1" = add permission */
929 struct permission_alias * next;
934 * Note: this is special-cased in the code so we don't need to
935 * fill in the ->next fields.
937 static const struct permission_alias standard_aliases[] =
939 { "+block", PERMIT_MASK_ALL, PERMIT_BLOCK },
940 /* { "+cookies", PERMIT_MASK_ALL, PERMIT_COOKIE_SET | PERMIT_COOKIE_READ }, */
941 { "+cookies-read", PERMIT_MASK_ALL, PERMIT_COOKIE_READ },
942 { "+cookies-set", PERMIT_MASK_ALL, PERMIT_COOKIE_SET },
943 { "+fast-redirects", PERMIT_MASK_ALL, PERMIT_FAST_REDIRECTS },
944 { "+filter", PERMIT_MASK_ALL, PERMIT_RE_FILTER },
945 { "+image", PERMIT_MASK_ALL, PERMIT_IMAGE },
946 { "+popup", PERMIT_MASK_ALL, PERMIT_POPUPS },
947 { "+popups", PERMIT_MASK_ALL, PERMIT_POPUPS },
948 { "+referer", PERMIT_MASK_ALL, PERMIT_REFERER },
949 { "+referrer", PERMIT_MASK_ALL, PERMIT_REFERER },
950 { "-block", ~PERMIT_BLOCK, 0 },
951 /* { "-cookies", ~(PERMIT_COOKIE_SET | PERMIT_COOKIE_READ), 0 }, */
952 { "-cookies-read", ~PERMIT_COOKIE_READ, 0 },
953 { "-cookies-set", ~PERMIT_COOKIE_SET, 0 },
954 { "-fast-redirects", ~PERMIT_FAST_REDIRECTS, 0 },
955 { "-filter", ~PERMIT_RE_FILTER, 0 },
956 { "-image", ~PERMIT_IMAGE, 0 },
957 { "-popup", ~PERMIT_POPUPS, 0 },
958 { "-popups", ~PERMIT_POPUPS, 0 },
959 { "-referer", ~PERMIT_REFERER, 0 },
960 { "-referrer", ~PERMIT_REFERER, 0 },
961 { NULL, 0, 0 } /* End marker */
965 /*********************************************************************
967 * Function : load_permissions_file
969 * Description : Read and parse a permissions file and add to files
973 * 1 : csp = Current client state (buffers, headers, etc...)
975 * Returns : 0 => Ok, everything else is an error.
977 *********************************************************************/
978 int load_permissions_file(struct client_state *csp)
982 struct permissions_spec *last_perm;
983 struct permissions_spec *perm;
985 struct file_list *fs;
986 #define MODE_START_OF_FILE 1
987 #define MODE_PERMISSIONS 2
989 int mode = MODE_START_OF_FILE;
990 unsigned curmask = PERMIT_MASK_ALL;
992 struct permission_alias * alias_list = NULL;
994 if (!check_file_changed(current_permissions_file, csp->config->permissions_file, &fs))
996 /* No need to load */
999 csp->permissions_list = current_permissions_file;
1005 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': error finding file: %E",
1006 csp->config->permissions_file);
1007 return 1; /* never get here */
1010 fs->f = last_perm = (struct permissions_spec *)zalloc(sizeof(*last_perm));
1011 if (last_perm == NULL)
1013 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': out of memory!",
1014 csp->config->permissions_file);
1015 return 1; /* never get here */
1018 if ((fp = fopen(csp->config->permissions_file, "r")) == NULL)
1020 log_error(LOG_LEVEL_FATAL, "can't load permissions file '%s': error opening file: %E",
1021 csp->config->permissions_file);
1022 return 1; /* never get here */
1025 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1029 /* It's a header block */
1032 /* It's {{settings}} or {{alias}} */
1033 int len = strlen(buf);
1034 char * start = buf + 2;
1035 char * end = buf + len - 1;
1036 if ((len < 5) || (*end-- != '}') || (*end-- != '}'))
1040 log_error(LOG_LEVEL_FATAL,
1041 "can't load permissions file '%s': invalid line: %s",
1042 csp->config->permissions_file, buf);
1043 return 1; /* never get here */
1046 /* Trim leading and trailing whitespace. */
1054 log_error(LOG_LEVEL_FATAL,
1055 "can't load permissions file '%s': invalid line: {{ }}",
1056 csp->config->permissions_file);
1057 return 1; /* never get here */
1060 if (0 == strcmpic(start, "alias"))
1062 /* it's an {{alias}} block */
1068 /* invalid {{something}} block */
1070 log_error(LOG_LEVEL_FATAL,
1071 "can't load permissions file '%s': invalid line: {{%s}}",
1072 csp->config->permissions_file, start);
1073 return 1; /* never get here */
1078 /* It's a permissions block */
1082 int len = strlen(buf);
1083 char * start = buf + 1;
1084 char * end = buf + len - 1;
1086 if ((len < 3) || (*end-- != '}'))
1090 log_error(LOG_LEVEL_FATAL,
1091 "can't load permissions file '%s': invalid line: %s",
1092 csp->config->permissions_file, buf);
1093 return 1; /* never get here */
1103 log_error(LOG_LEVEL_FATAL,
1104 "can't load permissions file '%s': invalid line: { }",
1105 csp->config->permissions_file);
1106 return 1; /* never get here */
1109 mode = MODE_PERMISSIONS;
1111 curmask = PERMIT_MASK_ALL;
1116 const struct permission_alias * alias = standard_aliases;
1117 char * option = start;
1118 while ((*start != '\0') && (*start != ' ') && (*start != '\t'))
1123 more = (*start != 0);
1128 /* Eat all the whitespace between the options */
1129 while ((*start == ' ') || (*start == '\t'))
1135 /* handle option in 'option' */
1137 /* Check for standard permission name */
1138 while ( (alias->name != NULL) && (0 != strcmpic(alias->name, option)) )
1142 if (alias->name == NULL)
1144 /* try user aliases. */
1146 while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) )
1148 alias = alias->next;
1153 /* Bad permission name */
1155 log_error(LOG_LEVEL_FATAL,
1156 "can't load permissions file '%s': invalid permission name: %s",
1157 csp->config->permissions_file, option);
1158 return 1; /* never get here */
1160 curmask &= alias->mask;
1161 curadd &= alias->mask;
1162 curadd |= alias->add;
1166 else if (mode == MODE_ALIAS)
1168 /* define an alias */
1169 struct permission_alias * new_alias;
1172 char * start = strchr(buf, '=');
1175 if ((start == NULL) || (start == buf))
1177 log_error(LOG_LEVEL_FATAL,
1178 "can't load permissions file '%s': invalid alias line: %s",
1179 csp->config->permissions_file, buf);
1180 return 1; /* never get here */
1183 if ((new_alias = zalloc(sizeof(*new_alias))) == NULL)
1186 log_error(LOG_LEVEL_FATAL,
1187 "can't load permissions file '%s': out of memory!",
1188 csp->config->permissions_file);
1189 return 1; /* never get here */
1192 /* Eat any the whitespace after the '=' */
1194 while ((*start == ' ') || (*start == '\t'))
1200 log_error(LOG_LEVEL_FATAL,
1201 "can't load permissions file '%s': invalid alias line: %s",
1202 csp->config->permissions_file, buf);
1203 return 1; /* never get here */
1206 /* Eat any the whitespace before the '=' */
1208 while ((*end == ' ') || (*end == '\t'))
1211 * we already know we must have at least 1 non-ws char
1212 * at start of buf - no need to check
1218 new_alias->name = strdup(buf);
1220 curmask = PERMIT_MASK_ALL;
1225 const struct permission_alias * alias = standard_aliases;
1226 char * option = start;
1227 while ((*start != '\0') && (*start != ' ') && (*start != '\t'))
1232 more = (*start != 0);
1237 /* Eat all the whitespace between the options */
1238 while ((*start == ' ') || (*start == '\t'))
1244 /* handle option in 'option' */
1246 /* Check for standard permission name */
1247 while ( (alias->name != NULL) && (0 != strcmpic(alias->name, option)) )
1251 if (alias->name == NULL)
1253 /* try user aliases. */
1255 while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) )
1257 alias = alias->next;
1262 /* Bad permission name */
1264 log_error(LOG_LEVEL_FATAL,
1265 "can't load permissions file '%s': invalid permission name: %s",
1266 csp->config->permissions_file, option);
1267 return 1; /* never get here */
1269 curmask &= alias->mask;
1270 curadd &= alias->mask;
1271 curadd |= alias->add;
1274 /* save alias permissions */
1275 new_alias->mask = curmask;
1276 new_alias->add = curadd;
1279 new_alias->next = alias_list;
1280 alias_list = new_alias;
1282 else if (mode == MODE_PERMISSIONS)
1284 /* it's a URL pattern */
1286 /* allocate a new node */
1287 if ((perm = zalloc(sizeof(*perm))) == NULL)
1290 log_error(LOG_LEVEL_FATAL,
1291 "can't load permissions file '%s': out of memory!",
1292 csp->config->permissions_file);
1293 return 1; /* never get here */
1297 perm->mask = curmask;
1300 /* Save the URL pattern */
1301 if (create_url_spec(perm->url, buf))
1304 log_error(LOG_LEVEL_FATAL,
1305 "can't load permissions file '%s': cannot create URL permission from: %s",
1306 csp->config->permissions_file, buf);
1307 return 1; /* never get here */
1310 /* add it to the list */
1311 last_perm->next = perm;
1314 else if (mode == MODE_START_OF_FILE)
1316 /* oops - please have a {} line as 1st line in file. */
1318 log_error(LOG_LEVEL_FATAL,
1319 "can't load permissions file '%s': first line is invalid: %s",
1320 csp->config->permissions_file, buf);
1321 return 1; /* never get here */
1325 /* How did we get here? This is impossible! */
1327 log_error(LOG_LEVEL_FATAL,
1328 "can't load permissions file '%s': INTERNAL ERROR - mode = %d",
1329 csp->config->permissions_file, mode);
1330 return 1; /* never get here */
1336 while (alias_list != NULL)
1338 struct permission_alias * next = alias_list->next;
1339 freez((char *)alias_list->name);
1344 #ifndef SPLIT_PROXY_ARGS
1345 if (!suppress_blocklists)
1347 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1349 #endif /* ndef SPLIT_PROXY_ARGS */
1351 /* the old one is now obsolete */
1352 if (current_permissions_file)
1354 current_permissions_file->unloader = unload_permissions_file;
1357 fs->next = files->next;
1359 current_permissions_file = fs;
1363 csp->permissions_list = fs;
1372 /*********************************************************************
1374 * Function : load_trustfile
1376 * Description : Read and parse a trustfile and add to files list.
1379 * 1 : csp = Current client state (buffers, headers, etc...)
1381 * Returns : 0 => Ok, everything else is an error.
1383 *********************************************************************/
1384 int load_trustfile(struct client_state *csp)
1388 struct block_spec *b, *bl;
1389 struct url_spec **tl;
1391 char buf[BUFSIZ], *p, *q;
1392 int reject, trusted;
1393 struct file_list *fs;
1395 if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
1397 /* No need to load */
1400 csp->tlist = current_trustfile;
1406 goto load_trustfile_error;
1409 fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1412 goto load_trustfile_error;
1415 if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
1417 goto load_trustfile_error;
1420 tl = csp->config->trust_list;
1422 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1438 while ((*p++ = *q++))
1444 /* skip blank lines */
1450 /* allocate a new node */
1451 if ((b = zalloc(sizeof(*b))) == NULL)
1454 goto load_trustfile_error;
1457 /* add it to the list */
1463 /* Save the URL pattern */
1464 if (create_url_spec(b->url, buf))
1467 goto load_trustfile_error;
1471 * save a pointer to URL's spec in the list of trusted URL's, too
1483 #ifndef SPLIT_PROXY_ARGS
1484 if (!suppress_blocklists)
1486 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1488 #endif /* ndef SPLIT_PROXY_ARGS */
1490 /* the old one is now obsolete */
1491 if (current_trustfile)
1493 current_trustfile->unloader = unload_trustfile;
1496 fs->next = files->next;
1498 current_trustfile = fs;
1507 load_trustfile_error:
1508 log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1509 csp->config->trustfile);
1513 #endif /* def TRUST_FILES */
1516 /*********************************************************************
1518 * Function : load_forwardfile
1520 * Description : Read and parse a forwardfile and add to files list.
1523 * 1 : csp = Current client state (buffers, headers, etc...)
1525 * Returns : 0 => Ok, everything else is an error.
1527 *********************************************************************/
1528 int load_forwardfile(struct client_state *csp)
1532 struct forward_spec *b, *bl;
1537 struct file_list *fs;
1538 const struct gateway *gw;
1540 if (!check_file_changed(current_forwardfile, csp->config->forwardfile, &fs))
1542 /* No need to load */
1545 csp->flist = current_forwardfile;
1551 goto load_forwardfile_error;
1554 fs->f = bl = (struct forward_spec *)zalloc(sizeof(*bl));
1556 if ((fs == NULL) || (bl == NULL))
1558 goto load_forwardfile_error;
1561 if ((fp = fopen(csp->config->forwardfile, "r")) == NULL)
1563 goto load_forwardfile_error;
1568 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1574 n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1578 log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1582 strcpy(buf, vec[0]);
1584 /* skip lines containing only ~ */
1590 /* allocate a new node */
1591 if (((b = zalloc(sizeof(*b))) == NULL)
1595 goto load_forwardfile_error;
1598 /* add it to the list */
1602 /* Save the URL pattern */
1603 if (create_url_spec(b->url, buf))
1606 goto load_forwardfile_error;
1609 /* now parse the gateway specs */
1613 for (gw = gateways; gw->name; gw++)
1615 if (strcmp(gw->name, p) == 0)
1621 if (gw->name == NULL)
1623 goto load_forwardfile_error;
1626 /* save this as the gateway type */
1629 /* now parse the gateway host[:port] spec */
1632 if (strcmp(p, ".") != 0)
1634 b->gw->gateway_host = strdup(p);
1636 if ((p = strchr(b->gw->gateway_host, ':')))
1639 b->gw->gateway_port = atoi(p);
1642 if (b->gw->gateway_port <= 0)
1644 goto load_forwardfile_error;
1648 /* now parse the forwarding spec */
1651 if (strcmp(p, ".") != 0)
1653 b->gw->forward_host = strdup(p);
1655 if ((p = strchr(b->gw->forward_host, ':')))
1658 b->gw->forward_port = atoi(p);
1661 if (b->gw->forward_port <= 0)
1663 b->gw->forward_port = 8000;
1672 #ifndef SPLIT_PROXY_ARGS
1673 if (!suppress_blocklists)
1675 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1677 #endif /* ndef SPLIT_PROXY_ARGS */
1679 /* the old one is now obsolete */
1680 if (current_forwardfile)
1682 current_forwardfile->unloader = unload_forwardfile;
1685 fs->next = files->next;
1687 current_forwardfile = fs;
1696 load_forwardfile_error:
1697 log_error(LOG_LEVEL_FATAL, "can't load forwardfile '%s': %E",
1698 csp->config->forwardfile);
1705 /*********************************************************************
1707 * Function : load_re_filterfile
1709 * Description : Load the re_filterfile. Each non-comment, non-empty
1710 * line is instantly added to the joblist, which is
1711 * a chained list of pcrs_job structs.
1714 * 1 : csp = Current client state (buffers, headers, etc...)
1716 * Returns : 0 => Ok, everything else is an error.
1718 *********************************************************************/
1719 int load_re_filterfile(struct client_state *csp)
1723 struct re_filterfile_spec *bl;
1724 struct file_list *fs;
1730 if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1732 /* No need to load */
1735 csp->rlist = current_re_filterfile;
1741 goto load_re_filterfile_error;
1744 fs->f = bl = (struct re_filterfile_spec *)zalloc(sizeof(*bl));
1747 goto load_re_filterfile_error;
1750 /* Open the file or fail */
1751 if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1753 goto load_re_filterfile_error;
1756 /* Read line by line */
1757 while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1759 enlist( bl->patterns, buf );
1761 /* We have a meaningful line -> make it a job */
1762 if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1764 log_error(LOG_LEVEL_RE_FILTER,
1765 "Adding re_filter job %s failed with error %d.", buf, error);
1770 dummy->next = bl->joblist;
1771 bl->joblist = dummy;
1772 log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1778 #ifndef SPLIT_PROXY_ARGS
1779 if (!suppress_blocklists)
1781 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1783 #endif /* ndef SPLIT_PROXY_ARGS */
1785 /* the old one is now obsolete */
1786 if ( NULL != current_re_filterfile )
1788 current_re_filterfile->unloader = unload_re_filterfile;
1791 fs->next = files->next;
1793 current_re_filterfile = fs;
1802 load_re_filterfile_error:
1803 log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1804 csp->config->re_filterfile);
1808 #endif /* def PCRS */
1811 /*********************************************************************
1813 * Function : add_loader
1815 * Description : Called from `load_config'. Called once for each input
1816 * file found in config.
1819 * 1 : loader = pointer to a function that can parse and load
1820 * the appropriate config file.
1821 * 2 : config = The configuration_spec to add the loader to.
1825 *********************************************************************/
1826 void add_loader(int (*loader)(struct client_state *),
1827 struct configuration_spec * config)
1831 for (i=0; i < NLOADERS; i++)
1833 if (config->loaders[i] == NULL)
1835 config->loaders[i] = loader;
1843 /*********************************************************************
1845 * Function : run_loader
1847 * Description : Called from `load_config' and `listen_loop'. This
1848 * function keeps the "csp" current with any file mods
1849 * since the last loop. If a file is unchanged, the
1850 * loader functions do NOT reload the file.
1853 * 1 : csp = Current client state (buffers, headers, etc...)
1854 * Must be non-null. Reads: "csp->config"
1855 * Writes: various data members.
1857 * Returns : 0 => Ok, everything else is an error.
1859 *********************************************************************/
1860 int run_loader(struct client_state *csp)
1865 for (i=0; i < NLOADERS; i++)
1867 if (csp->config->loaders[i] == NULL)
1871 ret |= (csp->config->loaders[i])(csp);