-const char jcc_rcs[] = "$Id: jcc.c,v 1.92.2.16 2005/04/03 20:10:50 david__schmidt Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.104 2006/09/23 13:26:38 roro Exp $";
/*********************************************************************
*
- * File : $Source: /cvsroot/ijbswa/current/Attic/jcc.c,v $
+ * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $
*
* Purpose : Main file. Contains main() method, main loop, and
* the main connection-handling function.
*
* Revisions :
* $Log: jcc.c,v $
+ * Revision 1.104 2006/09/23 13:26:38 roro
+ * Replace TABs by spaces in source code.
+ *
+ * Revision 1.103 2006/09/21 12:54:43 fabiankeil
+ * Fix +redirect{}. Didn't work with -fast-redirects.
+ *
+ * Revision 1.102 2006/09/06 13:03:04 fabiankeil
+ * Respond with 400 and a short text message
+ * if the client tries to use Privoxy as FTP proxy.
+ *
+ * Revision 1.101 2006/09/06 09:23:37 fabiankeil
+ * Make number of retries in case of forwarded-connect problems
+ * a config file option (forwarded-connect-retries) and use 0 as
+ * default.
+ *
+ * Revision 1.100 2006/09/03 19:42:59 fabiankeil
+ * Set random(3) seed.
+ *
+ * Revision 1.99 2006/09/02 15:36:42 fabiankeil
+ * Follow the OpenBSD port's lead and protect the resolve
+ * functions on OpenBSD as well.
+ *
+ * Revision 1.98 2006/08/24 11:01:34 fabiankeil
+ * --user fix. Only use the user as group if no group is specified.
+ * Solves BR 1492612. Thanks to Spinor S. and David Laight.
+ *
+ * Revision 1.97 2006/08/18 15:23:17 david__schmidt
+ * Windows service (re-)integration
+ *
+ * The new args are:
+ *
+ * --install[:service_name]
+ * --uninstall[:service_name]
+ * --service
+ *
+ * They work as follows:
+ * --install will create a service for you and then terminate.
+ * By default the service name will be "privoxy" (without the quotes).
+ * However you can run multiple services if you wish, just by adding
+ * a colon and then a name (no spaces).
+ *
+ * --uninstall follows the exact same rules a --install.
+ *
+ * --service is used when the program is executed by the service
+ * control manager, and in normal circumstances would never be
+ * used as a command line argument.
+ *
+ * Revision 1.96 2006/08/15 20:12:36 david__schmidt
+ * Windows service integration
+ *
+ * Revision 1.95 2006/08/03 02:46:41 david__schmidt
+ * Incorporate Fabian Keil's patch work:\rhttp://www.fabiankeil.de/sourcecode/privoxy/
+ *
+ * Revision 1.94 2006/07/18 14:48:46 david__schmidt
+ * Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
+ * with what was really the latest development (the v_3_0_branch branch)
+ *
* Revision 1.92.2.16 2005/04/03 20:10:50 david__schmidt
* Thanks to Jindrich Makovicka for a race condition fix for the log
* file. The race condition remains for non-pthread implementations.
# ifndef _WIN_CONSOLE
# include "w32log.h"
# endif /* ndef _WIN_CONSOLE */
+# include "w32svrapi.h"
#else /* ifndef _WIN32 */
#define sleep(N) DosSleep(((N) * 100))
#endif
+#if defined(OSX_DARWIN) || defined(__OpenBSD__)
#ifdef OSX_DARWIN
/*
* Hit OSX over the head with a hammer. Protect all *_r functions.
*/
pthread_mutex_t gmtime_mutex;
pthread_mutex_t localtime_mutex;
+#endif /* def OSX_DARWIN */
+/*
+ * Protect only the resolve functions for OpenBSD.
+ */
pthread_mutex_t gethostbyaddr_mutex;
pthread_mutex_t gethostbyname_mutex;
-#endif /* def OSX_DARWIN */
+#endif /* defined(OSX_DARWIN) || defined(__OpenBSD__) */
#ifdef FEATURE_PTHREAD
pthread_mutex_t log_mutex;
int server_body;
int ms_iis5_hack = 0;
int byte_count = 0;
+ unsigned int forwarded_connect_retries = 0;
+ unsigned int max_forwarded_connect_retries = csp->config->forwarded_connect_retries;
const struct forward_spec * fwd;
struct http_request *http;
int len; /* for buffer sizes */
return;
}
+ if (!strncmpic(http->cmd, "GET ftp://", 10))
+ {
+ strcpy(buf, FTP_RESPONSE);
+ write_socket(csp->cfd, buf, strlen(buf));
+
+ log_error(LOG_LEVEL_ERROR, "%s tried to use Privoxy as FTP proxy: %s",
+ csp->ip_addr_str, http->cmd);
+
+ free_http_request(http);
+ return;
+ }
+
/* decide how to route the HTTP request */
if ((fwd = forward_url(http, csp)) == NULL)
|| (csp->action->flags & ACTION_LIMIT_CONNECT
&& !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT], csp->http->port)) )
{
- strcpy(buf, CFORBIDDEN);
- write_socket(csp->cfd, buf, strlen(buf));
-
- log_error(LOG_LEVEL_CONNECT, "Denying suspicious CONNECT request from %s", csp->ip_addr_str);
- log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 403 0", csp->ip_addr_str);
-
- return;
+ if (csp->action->flags & ACTION_TREAT_FORBIDDEN_CONNECTS_LIKE_BLOCKS)
+ {
+ /* The response will violate the specs, but makes unblocking easier. */
+ log_error(LOG_LEVEL_ERROR, "Marking suspicious CONNECT request from %s for blocking.",
+ csp->ip_addr_str);
+ csp->action->flags |= ACTION_BLOCK;
+ http->ssl = 0;
+ }
+ else
+ {
+ strcpy(buf, CFORBIDDEN);
+ write_socket(csp->cfd, buf, strlen(buf));
+ log_error(LOG_LEVEL_CONNECT, "Denying suspicious CONNECT request from %s", csp->ip_addr_str);
+ log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 403 0", csp->ip_addr_str);
+ return;
+ }
}
}
/* ..or a fast redirect kicked in */
#ifdef FEATURE_FAST_REDIRECTS
- || (((csp->action->flags & ACTION_FAST_REDIRECTS) != 0) &&
- (NULL != (rsp = redirect_url(csp))))
+ || ( NULL != (rsp = redirect_url(csp)))
#endif /* def FEATURE_FAST_REDIRECTS */
))
)
csp->flags |= CSP_FLAG_REJECTED;
#endif /* def FEATURE_STATISTICS */
- /* Log (FIXME: All intercept reasons apprear as "crunch" with Status 200) */
+ /* Log (FIXME: All intercept reasons appear 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->ocmd);
/* here we connect to the server, gateway, or the forwarder */
- csp->sfd = forwarded_connect(fwd, http, csp);
+ while ( (csp->sfd = forwarded_connect(fwd, http, csp))
+ && (errno == EINVAL) && (forwarded_connect_retries++ < max_forwarded_connect_retries))
+ {
+ log_error(LOG_LEVEL_ERROR, "failed request #%u to connect to %s. Trying again.",
+ forwarded_connect_retries, http->hostport);
+ }
if (csp->sfd == JB_INVALID_SOCKET)
{
csp->content_length = csp->iob->eod - csp->iob->cur;
}
- hdr = sed(server_patterns, add_server_headers, csp);
+ hdr = sed(server_patterns_light, NULL, csp);
+
if (hdr == NULL)
{
/* FIXME Should handle error properly */
#endif
{
int argc_pos = 0;
+#ifdef HAVE_RANDOM
+ unsigned int random_seed;
+#endif /* ifdef HAVE_RANDOM */
#ifdef unix
struct passwd *pw = NULL;
struct group *grp = NULL;
*/
while (++argc_pos < argc)
{
+#ifdef _WIN32
+ /* Check to see if the service must be installed or uninstalled */
+ if (strncmp(argv[argc_pos], "--install", 9) == 0)
+ {
+ const char *pName = argv[argc_pos] + 9;
+ if (*pName == ':')
+ pName++;
+ exit( (install_service(pName)) ? 0 : 1 );
+ }
+ else if (strncmp(argv[argc_pos], "--uninstall", + 11) == 0)
+ {
+ const char *pName = argv[argc_pos] + 11;
+ if (*pName == ':')
+ pName++;
+ exit((uninstall_service(pName)) ? 0 : 1);
+ }
+ else if (strcmp(argv[argc_pos], "--service" ) == 0)
+ {
+ bRunAsService = TRUE;
+ w32_set_service_cwd();
+ atexit(w32_service_exit_notify);
+ }
+ else
+#endif /* defined(_WIN32) */
+
+
+#if !defined(_WIN32) || defined(_WIN_CONSOLE)
+
if (strcmp(argv[argc_pos], "--help") == 0)
{
usage(argv[0]);
}
#endif /* defined(unix) */
-
- else
+#endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
{
configfile = argv[argc_pos];
}
InitWin32();
#endif
-#ifdef OSX_DARWIN
+#if defined(OSX_DARWIN) || defined(__OpenBSD__)
/*
* Prepare global mutex semaphores
*/
+#ifdef OSX_DARWIN
pthread_mutex_init(&gmtime_mutex,0);
pthread_mutex_init(&localtime_mutex,0);
+#endif /* def OSX_DARWIN */
pthread_mutex_init(&gethostbyaddr_mutex,0);
pthread_mutex_init(&gethostbyname_mutex,0);
-#endif /* def OSX_DARWIN */
+#endif /* defined(OSX_DARWIN) || defined(__OpenBSD__) */
#ifdef FEATURE_PTHREAD
pthread_mutex_init(&log_mutex,0);
pthread_mutex_init(&log_init_mutex,0);
#endif /* FEATURE_PTHREAD */
+#ifdef HAVE_RANDOM
+ random_seed = (unsigned int)time(NULL);
+ srandom(random_seed);
+#endif /* ifdef HAVE_RANDOM */
+
/*
* Unix signal handling
*
for (idx = 0; catched_signals[idx] != 0; idx++)
{
+#ifdef sun /* FIXME: Is it safe to check for HAVE_SIGSET instead? */
+ if (sigset(catched_signals[idx], sig_handler) == SIG_ERR)
+#else
if (signal(catched_signals[idx], sig_handler) == SIG_ERR)
+#endif /* ifdef sun */
{
log_error(LOG_LEVEL_FATAL, "Can't set signal-handler for signal %d: %E", catched_signals[idx]);
}
if (NULL != pw)
{
- if (((NULL != grp) && setgid(grp->gr_gid)) || (setgid(pw->pw_gid)))
+ if (setgid((NULL != grp) ? grp->gr_gid : pw->pw_gid))
{
log_error(LOG_LEVEL_FATAL, "Cannot setgid(): Insufficient permissions.");
}
}
#endif /* defined unix */
+#ifdef _WIN32
+ /* This will be FALSE unless the command line specified --service
+ */
+ if (bRunAsService)
+ {
+ /* Yup, so now we must attempt to establish a connection
+ * with the service dispatcher. This will only work if this
+ * process was launched by the service control manager to
+ * actually run as a service. If this isn't the case, i've
+ * known it take around 30 seconds or so for the call to return.
+ */
+
+ /* The StartServiceCtrlDispatcher won't return until the service is stopping */
+ if (w32_start_service_ctrl_dispatcher(w32ServiceDispatchTable))
+ {
+ /* Service has run, and at this point is now being stopped, so just return */
+ return 0;
+ }
+
+#ifdef _WIN_CONSOLE
+ printf("Warning: Failed to connect to Service Control Dispatcher\nwhen starting as a service!\n");
+#endif
+ /* An error occurred. Usually it's because --service was wrongly specified
+ * and we were unable to connect to the Service Control Dispatcher because
+ * it wasn't expecting us and is therefore not listening.
+ *
+ * For now, just continue below to call the listen_loop function.
+ */
+ }
+#endif /* def _WIN32 */
+
listen_loop();
/* NOTREACHED */
}
+#ifdef _WIN32
+/* Without this simple workaround we get this compiler warning from _beginthread
+ * warning C4028: formal parameter 1 different from declaration
+ */
+void w32_service_listen_loop(void *p)
+{
+ listen_loop();
+}
+#endif /* def _WIN32 */
+
+
/*********************************************************************
*
* Function : listen_loop