X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=c367919f4cee9ef500863ca618259b3ec4161581;hp=3ec42191c183fa90a11aabf4cffd9ddbeeb8148c;hb=e37a59aca86ce1f33b5979f7456084b11919b3b7;hpb=7cadc7d4799218b7c62e48efec14729390039cc1 diff --git a/jcc.c b/jcc.c index 3ec42191..c367919f 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.63 2002/03/02 04:14:50 david__schmidt Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.75 2002/03/06 10:02:19 oes Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -33,6 +33,57 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.63 2002/03/02 04:14:50 david__schmidt Exp * * Revisions : * $Log: jcc.c,v $ + * Revision 1.75 2002/03/06 10:02:19 oes + * Fixed stupid bug when --user was not given + * + * Revision 1.74 2002/03/06 00:49:31 jongfoster + * Fixing warning on Windows + * Making #ifdefs that refer to the same variable consistently + * use #ifdef unix rather than mixing #ifdef unix & #ifndef OS2 + * + * Revision 1.73 2002/03/05 23:57:30 hal9 + * Stray character 's' on line 1618 was breaking build. + * + * Revision 1.72 2002/03/05 21:33:45 david__schmidt + * - Re-enable OS/2 building after new parms were added + * - Fix false out of memory report when resolving CGI templates when no IP + * address is available of failed attempt (a la no such domain) + * + * Revision 1.71 2002/03/05 18:13:56 oes + * Added --user option + * + * Revision 1.70 2002/03/05 04:52:42 oes + * Deleted non-errlog debugging code + * + * Revision 1.69 2002/03/04 23:50:00 jongfoster + * Splitting off bind_port() call into bind_port_helper(), with + * improved logging. + * + * Revision 1.68 2002/03/04 20:17:32 oes + * Fixed usage info + * + * Revision 1.67 2002/03/04 18:18:57 oes + * - Removed _DEBUG mode + * - Cleand up cmdline parsing + * - Introduced --no-daemon, --pidfile options + * - Cleaned up signal handling: + * - Terminate cleanly on INT, TERM and ABRT + * - Schedule logfile for re-opening on HUP + * - Ignore CHLD and PIPE + * - Leave the rest with their default handlers + * - Uniform handler registration + * - Added usage() function + * - Played styleguide police + * + * Revision 1.66 2002/03/03 15:06:55 oes + * Re-enabled automatic config reloading + * + * Revision 1.65 2002/03/03 14:49:11 oes + * Fixed CLF logging: Now uses client's original HTTP request + * + * Revision 1.64 2002/03/03 09:18:03 joergs + * Made jumbjuster work on AmigaOS again. + * * Revision 1.63 2002/03/02 04:14:50 david__schmidt * Clean up a little CRLF unpleasantness that suddenly appeared * @@ -434,6 +485,10 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.63 2002/03/02 04:14:50 david__schmidt Exp #include #endif /* sun */ +#ifdef unix +#include +#endif + # include # ifdef __BEOS__ @@ -456,10 +511,6 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.63 2002/03/02 04:14:50 david__schmidt Exp #endif -#ifdef _DEBUG -int ldebug = 0; -#endif - #include "project.h" #include "list.h" #include "jcc.h" @@ -479,11 +530,10 @@ int ldebug = 0; const char jcc_h_rcs[] = JCC_H_VERSION; const char project_h_rcs[] = PROJECT_H_VERSION; +int no_daemon = 0; struct client_state clients[1]; struct file_list files[1]; -short int MustReload = 0; - #ifdef FEATURE_STATISTICS int urls_read = 0; /* total nr of urls read inc rejected */ int urls_rejected = 0; /* total nr of urls rejected */ @@ -512,6 +562,8 @@ static int32 server_thread(void *data); #if defined(unix) const char *basedir; +const char *pidfile = NULL; +int received_hup_signal = 0; #endif /* defined unix */ /* The vanilla wafer. */ @@ -528,41 +580,50 @@ static const char VANILLA_WAFER[] = #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA) /********************************************************************* * - * Function : SIG_handler + * Function : sig_handler * * Description : Signal handler for different signals. - * see man kill, signal .. + * Exit gracefully on ABRT, TERM and INT + * or set a flag that will cause the errlog + * to be reopened by the main thread on HUP. * * Parameters : - * 1 : signal - the signal cause this function to call + * 1 : the_signal = the signal cause this function to call * * Returns : - * *********************************************************************/ -static void SIG_handler( int signal ) +static void sig_handler(int the_signal) { - switch( signal ) + switch(the_signal) { - case SIGHUP: - MustReload = 1; - break; + case SIGABRT: case SIGTERM: - log_error(LOG_LEVEL_INFO, "exiting by signal %d .. bye", signal); - + case SIGINT: + log_error(LOG_LEVEL_INFO, "exiting by signal %d .. bye", the_signal); #if defined(unix) - deletePidFile(); + unlink(pidfile); #endif /* unix */ - - exit( signal ); + exit(the_signal); break; + case SIGHUP: + received_hup_signal = 1; + break; + default: - /* want to exit jb so use FATAL */ - log_error(LOG_LEVEL_FATAL, "SIG_handler: receive signal %d without handler.", signal); + /* + * We shouldn't be here, unless we catch signals + * in main() that we can't handle here! + */ + log_error(LOG_LEVEL_FATAL, "sig_handler: exiting on unexpected signal %d", the_signal); } return; + } #endif + + /********************************************************************* * * Function : chat @@ -782,6 +843,16 @@ static void chat(struct client_state *csp) } } + /* + * Save a copy of the original request for logging + */ + http->ocmd = strdup(http->cmd); + + if (http->ocmd == NULL) + { + log_error(LOG_LEVEL_FATAL, "Out of memory copying HTTP request line"); + } + /* * (Re)build the HTTP request for non-SSL requests. * If forwarding, use the whole URL, else, use only the path. @@ -900,7 +971,7 @@ static void chat(struct client_state *csp) /* Log (FIXME: All intercept reasons apprear as "crunch" with Status 200) */ log_error(LOG_LEVEL_GPC, "%s%s crunch!", http->hostport, http->path); - log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", csp->ip_addr_str, http->cmd); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", csp->ip_addr_str, http->ocmd); /* Clean up and return */ free_http_response(rsp); @@ -933,14 +1004,14 @@ static void chat(struct client_state *csp) rsp = error_response(csp, "no-such-domain", errno); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 404 0", - csp->ip_addr_str, http->cmd); + csp->ip_addr_str, http->ocmd); } else { rsp = error_response(csp, "connect-failed", errno); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", - csp->ip_addr_str, http->cmd); + csp->ip_addr_str, http->ocmd); } @@ -984,7 +1055,7 @@ static void chat(struct client_state *csp) http->hostport); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", - csp->ip_addr_str, http->cmd); + csp->ip_addr_str, http->ocmd); rsp = error_response(csp, "connect-failed", errno); @@ -1010,7 +1081,7 @@ static void chat(struct client_state *csp) * client, flush the rest, and get out of the way. */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 2\n", - csp->ip_addr_str, http->cmd); + csp->ip_addr_str, http->ocmd); if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1) < 0) { @@ -1084,7 +1155,7 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_ERROR, "read from: %s failed: %E", http->host); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 503 0", - csp->ip_addr_str, http->cmd); + csp->ip_addr_str, http->ocmd); rsp = error_response(csp, "connect-failed", errno); @@ -1398,7 +1469,7 @@ static void chat(struct client_state *csp) } log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 %d", - csp->ip_addr_str, http->cmd, byte_count); + csp->ip_addr_str, http->ocmd, byte_count); } @@ -1456,6 +1527,28 @@ static int32 server_thread(void *data) #endif +/********************************************************************* + * + * Function : usage + * + * Description : Print usage info & exit. + * + * Parameters : Pointer to argv[0] for identifying ourselves + * + * Returns : No. ,-) + * + *********************************************************************/ +void usage(const char *myname) +{ + printf("JunkBuster proxy version " VERSION " (" HOME_PAGE_URL ")\n" + "Usage: %s [--help] [--version] [--no-daemon] [--pidfile pidfile] [--user user] [configfile]\n" + "Aborting.\n", myname); + + exit(2); + +} + + /********************************************************************* * * Function : main @@ -1485,7 +1578,13 @@ int real_main(int argc, const char *argv[]) int main(int argc, const char *argv[]) #endif { - int argc_pos = 1; + int argc_pos = 0; +#ifdef unix + struct passwd *pw = NULL; +#endif + + Argc = argc; + Argv = argv; configfile = #if !defined(_WIN32) @@ -1495,53 +1594,66 @@ int main(int argc, const char *argv[]) #endif ; -#if !defined(_WIN32) || defined(_WIN_CONSOLE) - if ((argc >= 2) && (strcmp(argv[1], "--help")==0)) - { - printf("JunkBuster proxy version " VERSION ".\n\n" - "Usage: %s [configfile]\n\n" - "See " HOME_PAGE_URL " for details.\n" - "This program is distributed under the GNU GPL, version 2 or later.\n", - argv[0]); - exit(2); - } - if ((argc >= 2) && (strcmp(argv[1], "--version")==0)) - { - printf(VERSION "\n"); - exit(2); - } -#ifdef _DEBUG - if ((argc >= 2) && (strcmp(argv[1], "-d")==0)) + /* + * Parse the command line arguments + */ + while (++argc_pos < argc) { - ldebug++; - argc_pos++; - fprintf(stderr,"debugging enabled..\n"); - } -#endif /* _DEBUG */ -#endif /* !defined(_WIN32) || defined(_WIN_CONSOLE) */ +#if !defined(_WIN32) || defined(_WIN_CONSOLE) - Argc = argc; - Argv = argv; + if (strcmp(argv[argc_pos], "--help") == 0) + { + usage(argv[0]); + } - if (argc > argc_pos ) - { - configfile = argv[argc_pos]; - } + else if(strcmp(argv[argc_pos], "--version") == 0) + { + printf("Junkbuster version " VERSION " (" HOME_PAGE_URL ")\n"); + exit(0); + } + + else if (strcmp(argv[argc_pos], "--no-daemon" ) == 0) + { + no_daemon = 1; + } +#if defined(unix) + else if (strcmp(argv[argc_pos], "--pidfile" ) == 0) + { + if (++argc_pos == argc) usage(argv[0]); + pidfile = strdup(argv[argc_pos]); + } + + else if (strcmp(argv[argc_pos], "--user" ) == 0) + { + if (++argc_pos == argc) usage(argv[0]); + pw = getpwnam(argv[argc_pos]); + + if (pw == NULL) + { + log_error(LOG_LEVEL_FATAL, "User %s not found.", argv[argc_pos]); + } + } +#endif /* defined(unix) */ + else +#endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */ + { + configfile = argv[argc_pos]; + } + + } /* -END- while (more arguments) */ #if defined(unix) if ( *configfile != '/' ) { char *abs_file; - DBG(1, ("configfile before '%s'\n",configfile) ); - /* make config-filename absolute here */ if ( !(basedir = getcwd( NULL, 1024 ))) { perror("get working dir failed"); exit( 1 ); } - DBG(1, ("working dir '%s'\n",basedir) ); + if ( !(abs_file = malloc( strlen( basedir ) + strlen( configfile ) + 5 ))) { perror("malloc failed"); @@ -1551,7 +1663,6 @@ int main(int argc, const char *argv[]) strcat( abs_file, "/" ); strcat( abs_file, configfile ); configfile = abs_file; - DBG(1, ("configfile after '%s'\n",configfile) ); } #endif /* defined unix */ @@ -1564,47 +1675,37 @@ int main(int argc, const char *argv[]) InitWin32(); #endif - + /* + * Unix signal handling + * + * Catch the abort, interrupt and terminate signals for a graceful exit + * Catch the hangup signal so the errlog can be reopened. + * Ignore the broken pipe and child signals + * FIXME: Isn't ignoring the default for SIGCHLD anyway and why ignore SIGPIPE? + */ #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA) { - int sig; - struct sigaction action; + int idx; + const int catched_signals[] = { SIGABRT, SIGTERM, SIGINT, SIGHUP, 0 }; + const int ignored_signals[] = { SIGPIPE, SIGCHLD, 0 }; - for ( sig = 1; sig < 16; sig++ ) + for (idx = 0; catched_signals[idx] != 0; idx++) { - switch( sig ) + if (signal(catched_signals[idx], sig_handler) == SIG_ERR) { - case 9: - case SIGPIPE: - case SIGCHLD: - case SIGHUP: - continue; + log_error(LOG_LEVEL_FATAL, "Can't set signal-handler for signal %d: %E", catched_signals[idx]); } - if ( signal(sig, SIG_handler) == SIG_ERR ) - log_error(LOG_LEVEL_FATAL, "Can't set signal-handler for signal %d: %E", sig); } - /* SIG_IGN */ - if ( signal(SIGPIPE, SIG_IGN) == SIG_ERR ) - log_error(LOG_LEVEL_FATAL, "Can't set SIG_IGN to SIGPIPE: %E"); - if ( signal(SIGCHLD, SIG_IGN) == SIG_ERR ) - log_error(LOG_LEVEL_FATAL, "Can't set SIG_IGN to SIGCHLD: %E"); - /* log file reload */ - if (!sigaction(SIGHUP,NULL,&action)) - { - action.sa_handler = &SIG_handler; - action.sa_flags = SA_RESTART; - if ( sigaction(SIGHUP,&action,NULL)) - log_error(LOG_LEVEL_FATAL, "Can't set signal-handler for signal SIGHUP: %E"); - } - else + for (idx = 0; ignored_signals[idx] != 0; idx++) { - perror("sigaction"); - log_error(LOG_LEVEL_FATAL, "Can't get sigaction data for signal SIGHUP"); + if (signal(ignored_signals[idx], SIG_IGN) == SIG_ERR) + { + log_error(LOG_LEVEL_FATAL, "Can't set ignore-handler for signal %d: %E", ignored_signals[idx]); + } } - -} +} #else /* ifdef _WIN32 */ # ifdef _WIN_CONSOLE /* @@ -1619,6 +1720,11 @@ int main(int argc, const char *argv[]) /* Initialize the CGI subsystem */ cgi_init_error_messages(); + /* + * If runnig on unix and without the --nodaemon + * option, become a daemon. I.e. fork, detach + * from tty and get process group leadership + */ #if defined(unix) { pid_t pid = 0; @@ -1626,73 +1732,75 @@ int main(int argc, const char *argv[]) int fd; #endif - /* - * we make us a real daemon - */ -#ifdef _DEBUG - if ( !ldebug) -#endif - pid = fork(); - if ( pid < 0 ) /* error */ - { - perror("fork"); - exit( 3 ); - } - else if ( pid != 0 ) /* parent */ + if (!no_daemon) { - int status; - pid_t wpid; - /* - * must check for errors - * child died due to missing files aso - */ - sleep( 1 ); - wpid = waitpid( pid, &status, WNOHANG ); - if ( wpid != 0 ) + pid = fork(); + + if ( pid < 0 ) /* error */ { - exit( 1 ); + perror("fork"); + exit( 3 ); } - exit( 0 ); - } - /* child */ + else if ( pid != 0 ) /* parent */ + { + int status; + pid_t wpid; + /* + * must check for errors + * child died due to missing files aso + */ + sleep( 1 ); + wpid = waitpid( pid, &status, WNOHANG ); + if ( wpid != 0 ) + { + exit( 1 ); + } + exit( 0 ); + } + /* child */ #if 1 - /* Should be more portable, but not as well tested */ - setsid(); + /* Should be more portable, but not as well tested */ + setsid(); #else /* !1 */ #ifdef __FreeBSD__ - setpgrp(0,0); + setpgrp(0,0); #else /* ndef __FreeBSD__ */ - setpgrp(); + setpgrp(); #endif /* ndef __FreeBSD__ */ - fd = open("/dev/tty", O_RDONLY); - if ( fd ) - { - /* no error check here */ - ioctl( fd, TIOCNOTTY,0 ); - close ( fd ); - } -#endif /* !1 */ - /* should close stderr (fd 2) here too, but the test for existence - ** and load config file is done in listen_loop() and puts - ** some messages on stderr there. - */ -#ifdef _DEBUG - if ( !ldebug ) - { + fd = open("/dev/tty", O_RDONLY); + if ( fd ) + { + /* no error check here */ + ioctl( fd, TIOCNOTTY,0 ); + close ( fd ); + } +#endif /* 1 */ + /* FIXME: should close stderr (fd 2) here too, but the test + * for existence + * and load config file is done in listen_loop() and puts + * some messages on stderr there. + */ + close( 0 ); close( 1 ); + chdir("/"); + + } /* -END- if (!no_daemon) */ + + /* + * As soon as we have written the PID file, we can switch + * to the user ID indicated by the --user option + */ + write_pid_file(); + + if ((NULL != pw) && setuid(pw->pw_uid)) + { + log_error(LOG_LEVEL_FATAL, "Cannot setuid(): Insufficient permissions."); } -#else - close( 0 ); - close( 1 ); -#endif /* _DEBUG */ - chdir("/"); - writePidFile(); } #endif /* defined unix */ - DBG(1, ("call listen_loop() \n") ); listen_loop(); /* NOTREACHED */ @@ -1703,25 +1811,41 @@ int main(int argc, const char *argv[]) /********************************************************************* * - * Function : listen_loop + * Function : bind_port_helper * - * Description : bind the listen port and enter a "FOREVER" listening loop. + * Description : Bind the listen port. Handles logging, and aborts + * on failure. * - * Parameters : N/A + * Parameters : + * 1 : config = Junkbuster configuration. Specifies port + * to bind to. * - * Returns : Never. + * Returns : Port that was opened. * *********************************************************************/ -static void listen_loop(void) +static int bind_port_helper(struct configuration_spec * config) { - struct client_state *csp = NULL; int bfd; - struct configuration_spec * config; - - config = load_config(); - log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)", - config->haddr ? config->haddr : "INADDR_ANY", config->hport); + if ( (config->haddr != NULL) + && (config->haddr[0] == '1') + && (config->haddr[1] == '2') + && (config->haddr[2] == '7') + && (config->haddr[3] == '.') ) + { + log_error(LOG_LEVEL_INFO, "Listening on port %d for local connections only", + config->hport); + } + else if (config->haddr == NULL) + { + log_error(LOG_LEVEL_INFO, "Listening on port %d on all IP addresses", + config->hport); + } + else + { + log_error(LOG_LEVEL_INFO, "Listening on port %d on IP address %s", + config->hport, config->haddr); + } bfd = bind_port(config->haddr, config->hport); @@ -1734,11 +1858,36 @@ static void listen_loop(void) config->hport, config->hport ); /* shouldn't get here */ - return; + return -1; } config->need_bind = 0; + return bfd; +} + + +/********************************************************************* + * + * Function : listen_loop + * + * Description : bind the listen port and enter a "FOREVER" listening loop. + * + * Parameters : N/A + * + * Returns : Never. + * + *********************************************************************/ +static void listen_loop(void) +{ + struct client_state *csp = NULL; + int bfd; + struct configuration_spec * config; + + config = load_config(); + + bfd = bind_port_helper(config); + while (FOREVER) { #if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) @@ -1747,8 +1896,23 @@ static void listen_loop(void) /* zombie children */ } #endif /* !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */ + + /* + * Free data that was used by died threads + */ sweep(); +#if defined(unix) + /* + * Re-open the errlog after HUP signal + */ + if (received_hup_signal) + { + init_error_log(Argv[0], config->logfile, config->debug); + received_hup_signal = 0; + } +#endif + if ( NULL == (csp = (struct client_state *) zalloc(sizeof(*csp))) ) { log_error(LOG_LEVEL_FATAL, "malloc(%d) for csp failed: %E", sizeof(*csp)); @@ -1777,23 +1941,7 @@ static void listen_loop(void) close_socket(bfd); - log_error(LOG_LEVEL_CONNECT, "bind (%s, %d)", - config->haddr ? config->haddr : "INADDR_ANY", config->hport); - bfd = bind_port(config->haddr, config->hport); - - if (bfd < 0) - { - log_error(LOG_LEVEL_FATAL, "can't bind %s:%d: %E " - "- There may be another junkbuster or some other " - "proxy running on port %d", - (NULL != config->haddr) ? config->haddr : "INADDR_ANY", - config->hport, config->hport - ); - /* shouldn't get here */ - return; - } - - config->need_bind = 0; + bfd = bind_port_helper(config); } log_error(LOG_LEVEL_CONNECT, "accept connection ... ");