2 const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.13 2001/06/05 22:33:54 jongfoster Exp $";
3 /*********************************************************************
5 * File : $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
7 * Purpose : Loads settings from the configuration file into
8 * global variables. This file contains both the
9 * routine to load the configuration and the global
10 * variables it writes to.
12 * Copyright : Written by and Copyright (C) 2001 the SourceForge
13 * IJBSWA team. http://ijbswa.sourceforge.net
15 * Based on the Internet Junkbuster originally written
16 * by and Copyright (C) 1997 Anonymous Coders and
17 * Junkbusters Corporation. http://www.junkbusters.com
19 * This program is free software; you can redistribute it
20 * and/or modify it under the terms of the GNU General
21 * Public License as published by the Free Software
22 * Foundation; either version 2 of the License, or (at
23 * your option) any later version.
25 * This program is distributed in the hope that it will
26 * be useful, but WITHOUT ANY WARRANTY; without even the
27 * implied warranty of MERCHANTABILITY or FITNESS FOR A
28 * PARTICULAR PURPOSE. See the GNU General Public
29 * License for more details.
31 * The GNU General Public License should be included with
32 * this file. If not, you can view it at
33 * http://www.gnu.org/copyleft/gpl.html
34 * or write to the Free Software Foundation, Inc., 59
35 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 * Revision 1.13 2001/06/05 22:33:54 jongfoster
41 * Fixed minor memory leak.
42 * Also now uses make_path to prepend the pathnames.
44 * Revision 1.12 2001/06/05 20:04:09 jongfoster
45 * Now uses _snprintf() in place of snprintf() under Win32.
47 * Revision 1.11 2001/06/04 18:31:58 swa
48 * files are now prefixed with either `confdir' or `logdir'.
49 * `make redhat-dist' replaces both entries confdir and logdir
52 * Revision 1.10 2001/06/03 19:11:54 oes
53 * introduced confdir option
55 * Revision 1.10 2001/06/03 11:03:48 oes
62 * adapted to new enlist_unique arg format
66 * introduced confdir option
68 * filters.c filtrers.h
70 * extracted-CGI relevant stuff
78 * support for new cgi mechansim
82 * functions for new list type: "map"
83 * extended enlist_unique
90 * deleted const struct interceptors
98 * added struct http_response
99 * changes struct interceptors to struct cgi_dispatcher
100 * moved HTML stuff to cgi.h
109 * Revision 1.9 2001/06/01 20:06:24 jongfoster
110 * Removed support for "tinygif" option - moved to actions file.
112 * Revision 1.8 2001/05/31 21:27:13 jongfoster
113 * Removed many options from the config file and into the
114 * "actions" file: add_forwarded, suppress_vanilla_wafer,
115 * wafer, add_header, user_agent, referer, from
116 * Also globally replaced "permission" with "action".
118 * Revision 1.7 2001/05/29 09:50:24 jongfoster
119 * Unified blocklist/imagelist/permissionslist.
120 * File format is still under discussion, but the internal changes
123 * Also modified interceptor behaviour:
124 * - We now intercept all URLs beginning with one of the following
125 * prefixes (and *only* these prefixes):
127 * * http://ijbswa.sf.net/config/
128 * * http://ijbswa.sourceforge.net/config/
129 * - New interceptors "home page" - go to http://i.j.b/ to see it.
130 * - Internal changes so that intercepted and fast redirect pages
131 * are not replaced with an image.
132 * - Interceptors now have the option to send a binary page direct
133 * to the client. (i.e. ijb-send-banner uses this)
134 * - Implemented show-url-info interceptor. (Which is why I needed
135 * the above interceptors changes - a typical URL is
136 * "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
137 * The previous mechanism would not have intercepted that, and
138 * if it had been intercepted then it then it would have replaced
141 * Revision 1.6 2001/05/26 00:28:36 jongfoster
142 * Automatic reloading of config file.
143 * Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
144 * Most of the global variables have been moved to a new
145 * struct configuration_spec, accessed through csp->config->globalname
146 * Most of the globals remaining are used by the Win32 GUI.
148 * Revision 1.5 2001/05/25 22:34:30 jongfoster
151 * Revision 1.4 2001/05/22 18:46:04 oes
153 * - Enabled filtering banners by size rather than URL
154 * by adding patterns that replace all standard banner
155 * sizes with the "Junkbuster" gif to the re_filterfile
157 * - Enabled filtering WebBugs by providing a pattern
158 * which kills all 1x1 images
160 * - Added support for PCRE_UNGREEDY behaviour to pcrs,
161 * which is selected by the (nonstandard and therefore
162 * capital) letter 'U' in the option string.
163 * It causes the quantifiers to be ungreedy by default.
164 * Appending a ? turns back to greedy (!).
166 * - Added a new interceptor ijb-send-banner, which
167 * sends back the "Junkbuster" gif. Without imagelist or
168 * MSIE detection support, or if tinygif = 1, or the
169 * URL isn't recognized as an imageurl, a lame HTML
170 * explanation is sent instead.
172 * - Added new feature, which permits blocking remote
173 * script redirects and firing back a local redirect
175 * The feature is conditionally compiled, i.e. it
176 * can be disabled with --disable-fast-redirects,
177 * plus it must be activated by a "fast-redirects"
178 * line in the config file, has its own log level
179 * and of course wants to be displayed by show-proxy-args
180 * Note: Boy, all the #ifdefs in 1001 locations and
181 * all the fumbling with configure.in and acconfig.h
182 * were *way* more work than the feature itself :-(
184 * - Because a generic redirect template was needed for
185 * this, tinygif = 3 now uses the same.
187 * - Moved GIFs, and other static HTTP response templates
192 * - Removed some >400 CRs again (Jon, you really worked
195 * Revision 1.3 2001/05/20 01:21:20 jongfoster
196 * Version 2.9.4 checkin.
197 * - Merged popupfile and cookiefile, and added control over PCRS
198 * filtering, in new "permissionsfile".
199 * - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
200 * file error you now get a message box (in the Win32 GUI) rather
201 * than the program exiting with no explanation.
202 * - Made killpopup use the PCRS MIME-type checking and HTTP-header
204 * - Removed tabs from "config"
205 * - Moved duplicated url parsing code in "loaders.c" to a new funcition.
206 * - Bumped up version number.
208 * Revision 1.2 2001/05/17 23:01:01 oes
209 * - Cleaned CRLF's from the sources and related files
211 * Revision 1.1.1.1 2001/05/15 13:58:58 oes
212 * Initial import of version 2.9.3 source tree
215 *********************************************************************/
221 #include <sys/types.h>
231 # include <sys/timeb.h>
232 # include <windows.h>
234 # include <process.h>
237 # endif /* def TOGGLE */
240 # ifndef _WIN_CONSOLE
242 # endif /* ndef _WIN_CONSOLE */
244 /* VC++ has "_snprintf", not "snprintf" */
245 #define snprintf _snprintf
247 #else /* ifndef _WIN32 */
250 # include <sys/time.h>
251 # include <sys/wait.h>
252 # include <sys/stat.h>
262 #include "showargs.h"
264 #include "killpopup.h"
265 #include "miscutil.h"
267 #include "jbsockets.h"
270 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
273 * Fix a problem with Solaris. There should be no effect on other
275 * Solaris's isspace() is a macro which uses it's argument directly
276 * as an array index. Therefore we need to make sure that high-bit
277 * characters generate +ve values, and ideally we also want to make
278 * the argument match the declared parameter type of "int".
280 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
281 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
284 /* by haroon - indicates if ijb is enabled */
285 int g_bToggleIJB = 1; /* JunkBusters is enabled by default. */
288 /* The filename of the configfile */
289 const char *configfile = NULL;
292 * The load_config function is now going to call `init_proxy_args',
293 * so it will need argc and argv. So we need to have these
294 * globally available.
297 const char **Argv = NULL;
299 static struct file_list *current_configfile = NULL;
303 * This takes the "cryptic" hash of each keyword and aliases them to
304 * something a little more readable. This also makes changing the
305 * hash values easier if they should change or the hash algorthm changes.
306 * Use the included "hash" program to find out what the hash will be
307 * for any string supplied on the command line. (Or just put it in the
308 * config file and read the number from the error message in the log).
312 #define hash_aclfile 1908516ul
313 #define hash_actions_file 3825730796ul /* FIXME "permissionsfile" */
314 #define hash_debug 78263ul
315 #define hash_confdir 1978389lu
316 #define hash_logdir 422889lu
317 #define hash_forwardfile 1268669141ul
318 #define hash_jarfile 2046641ul
319 #define hash_listen_address 1255650842ul
320 #define hash_logfile 2114766ul
321 #define hash_re_filterfile 3877522444ul
322 #define hash_single_threaded 4250084780ul
323 #define hash_suppress_blocklists 1948693308ul
324 #define hash_toggle 447966ul
325 #define hash_trust_info_url 449869467ul
326 #define hash_trustfile 56494766ul
328 #define hash_hide_console 2048809870ul
330 #define hash_activity_animation 1817904738ul
331 #define hash_close_button_minimizes 3651284693ul
332 #define hash_log_buffer_size 2918070425ul
333 #define hash_log_font_name 2866730124ul
334 #define hash_log_font_size 2866731014ul
335 #define hash_log_highlight_messages 4032101240ul
336 #define hash_log_max_lines 2868344173ul
337 #define hash_log_messages 2291744899ul
338 #define hash_show_on_task_bar 215410365ul
341 /*********************************************************************
343 * Function : unload_configfile
345 * Description : Free the config structure and all components.
348 * 1 : data: struct configuration_spec to unload
352 *********************************************************************/
353 void unload_configfile (void * data)
355 struct configuration_spec * config = (struct configuration_spec *)data;
358 if ( NULL != config->jar )
360 fclose( config->jar );
363 #endif /* def JAR_FILES */
365 freez((char *)config->confdir);
366 freez((char *)config->logdir);
368 freez((char *)config->haddr);
369 freez((char *)config->logfile);
371 freez((char *)config->actions_file);
372 freez((char *)config->forwardfile);
375 freez((char *)config->aclfile);
376 #endif /* def ACL_FILES */
379 freez((char *)config->jarfile);
380 #endif /* def JAR_FILES */
382 #ifndef SPLIT_PROXY_ARGS
383 freez((char *)config->suppress_message);
384 #endif /* ndef SPLIT_PROXY_ARGS */
387 freez((char *)config->re_filterfile);
388 #endif /* def PCRS */
393 /*********************************************************************
395 * Function : load_config
397 * Description : Load the config file and all parameters.
400 * 1 : csp = Client state (the config member will be
401 * filled in by this function).
403 * Returns : 0 => Ok, everything else is an error.
405 *********************************************************************/
406 struct configuration_spec * load_config(void)
410 FILE *configfp = NULL;
411 struct configuration_spec * config = NULL;
412 struct client_state * fake_csp;
413 struct file_list *fs;
415 if (!check_file_changed(current_configfile, configfile, &fs))
417 /* No need to load */
418 return ((struct configuration_spec *)current_configfile->f);
422 log_error(LOG_LEVEL_FATAL, "can't check configuration file '%s': %E",
426 log_error(LOG_LEVEL_INFO, "loading configuration file '%s':", configfile);
432 fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
438 log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
439 /* Never get here - LOG_LEVEL_FATAL causes program exit */
443 * This is backwards from how it's usually done.
444 * Following the usual pattern, "fs" would be stored in a member
445 * variable in "csp", and then we'd access "config" from "fs->f",
446 * using a cast. However, "config" is used so often that a
447 * cast each time would be very ugly, and the extra indirection
448 * would waste CPU cycles. Therefore we store "config" in
449 * "csp->config", and "fs" in "csp->config->config_file_list".
451 config->config_file_list = fs;
453 init_proxy_args(Argc, Argv, config);
459 config->multi_threaded = 1;
460 config->hport = HADDR_PORT;
462 if ((configfp = fopen(configfile, "r")) == NULL)
464 log_error(LOG_LEVEL_FATAL, "can't open configuration file '%s': %E",
466 /* Never get here - LOG_LEVEL_FATAL causes program exit */
469 while (read_config_line(buf, sizeof(buf), configfp, fs) != NULL)
477 /* Copy command (i.e. up to space or tab) into cmd */
480 while (*p && (*p != ' ') && (*p != '\t'))
486 /* Skip over the whitespace in buf */
487 while (*p && ((*p == ' ') || (*p == '\t')))
492 /* Copy the argument into arg */
495 /* Should never happen, but check this anyway */
501 /* Make sure the command field is lower case */
506 *p = ijb_tolower(*p);
510 /* Save the argument for show-proxy-args */
511 savearg(cmd, arg, config);
514 switch( hash_string( cmd ) )
517 case hash_trustfile :
518 freez((char *)config->trustfile);
519 config->trustfile = make_path(config->confdir, arg);
522 case hash_trust_info_url :
523 enlist(config->trust_info, arg);
525 #endif /* def TRUST_FILES */
528 config->debug |= atoi(arg);
532 freez((char *)config->confdir);
533 config->confdir = strdup(arg);
537 freez((char *)config->logdir);
538 config->logdir = strdup(arg);
541 case hash_single_threaded :
542 config->multi_threaded = 0;
545 case hash_actions_file :
546 freez((char *)config->actions_file);
547 config->actions_file = make_path(config->confdir, arg);
551 freez((char *)config->logfile);
552 config->logfile = make_path(config->logdir, arg);
557 freez((char *)config->jarfile);
558 config->jarfile = make_path(config->logdir, arg);
560 #endif /* def JAR_FILES */
562 case hash_listen_address :
563 freez((char *)config->haddr);
564 config->haddr = strdup(arg);
567 case hash_forwardfile :
568 freez((char *)config->forwardfile);
569 config->forwardfile = make_path(config->confdir, arg);
574 freez((char *)config->aclfile);
575 config->aclfile = make_path(config->confdir, arg);
577 #endif /* def ACL_FILES */
580 case hash_re_filterfile :
581 freez((char *)config->re_filterfile);
582 config->re_filterfile = make_path(config->confdir, arg);
584 #endif /* def PCRS */
587 case hash_hide_console :
590 #endif /*def _WIN_CONSOLE*/
592 #ifndef SPLIT_PROXY_ARGS
593 case hash_suppress_blocklists :
596 config->suppress_message = strdup(arg);
600 /* There will be NO reference in proxy-args. */
601 config->suppress_message = NULL;
604 config->suppress_blocklists = 1;
606 #endif /* ndef SPLIT_PROXY_ARGS */
610 g_bToggleIJB = atoi(arg);
612 #endif /* def TOGGLE */
614 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
615 case hash_activity_animation :
616 g_bShowActivityAnimation = atoi(arg);
619 case hash_log_messages :
620 g_bLogMessages = atoi(arg);
623 case hash_log_highlight_messages :
624 g_bHighlightMessages = atoi(arg);
627 case hash_log_buffer_size :
628 g_bLimitBufferSize = atoi(arg);
631 case hash_log_max_lines :
632 g_nMaxBufferLines = atoi(arg);
635 case hash_log_font_name :
636 strcpy( g_szFontFaceName, arg );
639 case hash_log_font_size :
640 g_nFontSize = atoi(arg);
643 case hash_show_on_task_bar :
644 g_bShowOnTaskBar = atoi(arg);
647 case hash_close_button_minimizes :
648 g_bCloseHidesWindow = atoi(arg);
650 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
652 /* Warnings about unsupported features */
655 case hash_re_filterfile :
656 #endif /* ndef PCRS */
659 #endif /* ndef TOGGLE */
660 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
661 case hash_activity_animation :
662 case hash_log_messages :
663 case hash_log_highlight_messages :
664 case hash_log_buffer_size :
665 case hash_log_max_lines :
666 case hash_log_font_name :
667 case hash_log_font_size :
668 case hash_show_on_task_bar :
669 case hash_close_button_minimizes :
670 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
672 case hash_hide_console :
673 #endif /* ndef _WIN_CONSOLE */
676 #endif /* ndef JAR_FILES */
679 #endif /* ndef ACL_FILES */
680 #ifdef SPLIT_PROXY_ARGS
681 case hash_suppress_blocklists :
682 #endif /* def SPLIT_PROXY_ARGS */
683 log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd);
688 * I decided that I liked this better as a warning than an
689 * error. To change back to an error, just change log level
690 * to LOG_LEVEL_FATAL.
692 log_error(LOG_LEVEL_ERROR, "Unrecognized directive (%lulu) in "
693 "configuration file: \"%s\"", hash_string( cmd ), buf);
694 p = malloc( BUFSIZ );
697 sprintf( p, "<br>\nWARNING: unrecognized directive : %s<br><br>\n", buf );
698 config->proxy_args_invocation = strsav( config->proxy_args_invocation, p );
702 } /* end switch( hash_string(cmd) ) */
703 } /* end while ( read_config_line(...) ) */
707 init_error_log(Argv[0], config->logfile, config->debug);
709 if (config->actions_file)
711 add_loader(load_actions_file, config);
714 if (config->forwardfile)
716 add_loader(load_forwardfile, config);
722 add_loader(load_aclfile, config);
724 #endif /* def ACL_FILES */
727 if (config->re_filterfile)
729 add_loader(load_re_filterfile, config);
731 #endif /* def PCRS */
734 if (config->trustfile)
736 add_loader(load_trustfile, config);
741 if ( NULL != config->jarfile )
743 if ( NULL == (config->jar = fopen(config->jarfile, "a")) )
745 log_error(LOG_LEVEL_FATAL, "can't open jarfile '%s': %E", config->jarfile);
746 /* Never get here - LOG_LEVEL_FATAL causes program exit */
748 setbuf(config->jar, NULL);
750 #endif /* def JAR_FILES */
752 if ( NULL == config->haddr )
754 config->haddr = strdup( HADDR_DEFAULT );
757 if ( NULL != config->haddr )
759 if ((p = strchr(config->haddr, ':')))
764 config->hport = atoi(p);
768 if (config->hport <= 0)
771 log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
772 /* Never get here - LOG_LEVEL_FATAL causes program exit */
774 if (*config->haddr == '\0')
776 config->haddr = NULL;
781 * Want to run all the loaders once now.
783 * Need to set up a fake csp, so they can get to the config.
785 fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp));
786 fake_csp->config = config;
788 if (run_loader(fake_csp))
791 log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
792 /* Never get here - LOG_LEVEL_FATAL causes program exit */
796 #ifndef SPLIT_PROXY_ARGS
797 if (!suppress_blocklists)
799 fs->proxy_args = strsav(fs->proxy_args, "</pre>");
801 #endif /* ndef SPLIT_PROXY_ARGS */
803 /* FIXME: this is a kludge for win32 */
804 #if defined(_WIN32) && !defined (_WIN_CONSOLE)
806 g_actions_file = config->actions_file;
807 g_forwardfile = config->forwardfile;
809 g_aclfile = config->aclfile;
810 #endif /* def ACL_FILES */
812 g_re_filterfile = config->re_filterfile;
815 g_trustfile = config->trustfile;
819 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
820 /* FIXME: end kludge */
823 config->need_bind = 1;
825 if (current_configfile)
827 struct configuration_spec * oldcfg = (struct configuration_spec *)
828 current_configfile->f;
830 * Check if config->haddr,hport == oldcfg->haddr,hport
832 * The following could be written more compactly as a single,
833 * (unreadably long) if statement.
835 config->need_bind = 0;
836 if (config->hport != oldcfg->hport)
838 config->need_bind = 1;
840 else if (config->haddr == NULL)
842 if (oldcfg->haddr != NULL)
844 config->need_bind = 1;
847 else if (oldcfg->haddr == NULL)
849 config->need_bind = 1;
851 else if (0 != strcmp(config->haddr, oldcfg->haddr))
853 config->need_bind = 1;
856 current_configfile->unloader = unload_configfile;
859 fs->next = files->next;
862 current_configfile = fs;