-const char jcc_rcs[] = "$Id: jcc.c,v 1.99 2006/09/02 15:36:42 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.110 2006/12/13 14:52:53 etresoft Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jcc.c,v $
*
* Revisions :
* $Log: jcc.c,v $
+ * Revision 1.110 2006/12/13 14:52:53 etresoft
+ * Fix build failure on MacOS X. Global symbols can be either static or extern, but not both.
+ *
+ * Revision 1.109 2006/12/06 19:41:40 fabiankeil
+ * Privoxy is now able to run as intercepting
+ * proxy in combination with any packet filter
+ * that does the port redirection. The destination
+ * is extracted from the "Host:" header which
+ * should be available for nearly all requests.
+ *
+ * Moved HTTP snipplets into jcc.c.
+ * Added error message for gopher proxy requests.
+ *
+ * Revision 1.108 2006/11/28 15:38:51 fabiankeil
+ * Only unlink the pidfile if it's actually used.
+ *
+ * Change order of interception checks to make
+ * it possible to block or redirect requests for
+ * the cgi pages.
+ *
+ * Revision 1.107 2006/11/13 19:05:51 fabiankeil
+ * Make pthread mutex locking more generic. Instead of
+ * checking for OSX and OpenBSD, check for FEATURE_PTHREAD
+ * and use mutex locking unless there is an _r function
+ * available. Better safe than sorry.
+ *
+ * Fixes "./configure --disable-pthread" and should result
+ * in less threading-related problems on pthread-using platforms,
+ * but it still doesn't fix BR#1122404.
+ *
+ * Revision 1.106 2006/11/06 19:58:23 fabiankeil
+ * Move pthread.h inclusion from jcc.c to jcc.h.
+ * Fixes build on x86-freebsd1 (FreeBSD 5.4-RELEASE).
+ *
+ * Revision 1.105 2006/11/06 14:26:02 fabiankeil
+ * Don't exit after receiving the second SIGHUP on Solaris.
+ *
+ * Fixes BR 1052235, but the same problem may exist on other
+ * systems. Once 3.0.6 is out we should use sigset()
+ * where available and see if it breaks anything.
+ *
+ * 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.
* 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/
+ * Incorporate Fabian Keil's patch work:
+http://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)
#include <fcntl.h>
#include <errno.h>
-#ifdef FEATURE_PTHREAD
-#include <pthread.h>
-#endif /* def FEATURE_PTHREAD */
-
#ifdef _WIN32
# ifndef FEATURE_PTHREAD
# ifndef STRICT
#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.
- */
+#ifdef FEATURE_PTHREAD
+pthread_mutex_t log_mutex;
+pthread_mutex_t log_init_mutex;
+
+#ifndef HAVE_GMTIME_R
pthread_mutex_t gmtime_mutex;
+#endif /* ndef HAVE_GMTIME_R */
+
+#ifndef HAVE_LOCALTIME_R
pthread_mutex_t localtime_mutex;
-#endif /* def OSX_DARWIN */
-/*
- * Protect only the resolve functions for OpenBSD.
- */
+#endif /* ndef HAVE_GMTIME_R */
+
+#ifndef HAVE_GETHOSTBYADDR_R
pthread_mutex_t gethostbyaddr_mutex;
-pthread_mutex_t gethostbyname_mutex;
-#endif /* defined(OSX_DARWIN) || defined(__OpenBSD__) */
+#endif /* ndef HAVE_GETHOSTBYADDR_R */
-#ifdef FEATURE_PTHREAD
-pthread_mutex_t log_mutex;
-pthread_mutex_t log_init_mutex;
+#ifndef HAVE_GETHOSTBYNAME_R
+pthread_mutex_t gethostbyname_mutex;
+#endif /* ndef HAVE_GETHOSTBYNAME_R */
#endif /* FEATURE_PTHREAD */
#if defined(unix) || defined(__EMX__)
"Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_"
"(copyright_or_otherwise)_applying_to_any_cookie._";
+/* HTTP snipplets. */
+const char CSUCCEED[] =
+ "HTTP/1.0 200 Connection established\n"
+ "Proxy-Agent: Privoxy/" VERSION "\r\n\r\n";
+
+const char CHEADER[] =
+ "HTTP/1.0 400 Invalid header received from browser\r\n"
+ "Connection: close\r\n\r\n"
+ "Invalid header received from browser.";
+
+const char CFORBIDDEN[] =
+ "HTTP/1.0 403 Connection not allowable\r\n"
+ "X-Hint: If you read this message interactively, then you know why this happens ,-)\r\n"
+ "Connection: close\r\n\r\n";
+
+const char FTP_RESPONSE[] =
+ "HTTP/1.0 400 Invalid request received from browser\r\n"
+ "Connection: close\r\n\r\n"
+ "Invalid request. Privoxy doesn't support FTP.\r\n";
+
+const char GOPHER_RESPONSE[] =
+ "HTTP/1.0 400 Invalid request received from browser\r\n"
+ "Connection: close\r\n\r\n"
+ "Invalid request. Privoxy doesn't support gopher.\r\n";
+
+const char MISSING_DESTINATION_RESPONSE[] =
+ "HTTP/1.0 400 Bad request received from browser\r\n"
+ "Connection: close\r\n\r\n"
+ "Bad request. Privoxy was unable to extract the destination.\r\n";
+
#if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA)
/*********************************************************************
{
switch(the_signal)
{
- case SIGABRT:
case SIGTERM:
case SIGINT:
log_error(LOG_LEVEL_INFO, "exiting by signal %d .. bye", the_signal);
#if defined(unix)
- unlink(pidfile);
+ if(pidfile)
+ {
+ unlink(pidfile);
+ }
#endif /* unix */
exit(the_signal);
break;
int server_body;
int ms_iis5_hack = 0;
int byte_count = 0;
- unsigned int socks_retries = 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 */
/* Skeleton for HTTP response, if we should intercept the request */
struct http_response *rsp;
+ /* Temporary copy of the client's headers before they get enlisted in csp->headers */
+ struct list header_list;
+ struct list *headers = &header_list;
+
http = csp->http;
/*
continue; /* more to come! */
}
+ /*
+ * If it's a FTP or gopher request, we don't support it.
+ *
+ * These checks are better than nothing, but they might
+ * not work in all configurations and some clients might
+ * have problems digesting the answer.
+ *
+ * They should, however, never cause more problems than
+ * Privoxy's old behaviour (returning the misleading HTML error message:
+ * "Could not resolve http://(ftp|gopher)://example.org").
+ */
+ if (!strncmpic(req, "GET ftp://", 10) || !strncmpic(req, "GET gopher://", 13))
+ {
+ if (!strncmpic(req, "GET ftp://", 10))
+ {
+ strcpy(buf, FTP_RESPONSE);
+ log_error(LOG_LEVEL_ERROR, "%s tried to use Privoxy as FTP proxy: %s",
+ csp->ip_addr_str, req);
+ }
+ else
+ {
+ strcpy(buf, GOPHER_RESPONSE);
+ log_error(LOG_LEVEL_ERROR, "%s tried to use Privoxy as gopher proxy: %s",
+ csp->ip_addr_str, req);
+ }
+ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, req);
+ freez(req);
+ write_socket(csp->cfd, buf, strlen(buf));
+ free_http_request(http);
+ return;
+ }
+
#ifdef FEATURE_FORCE_LOAD
/* If this request contains the FORCE_PREFIX,
* better get rid of it now and set the force flag --oes
#endif /* def FEATURE_FORCE_LOAD */
- parse_http_request(req, http, csp);
+ switch( parse_http_request(req, http, csp) )
+ {
+ case JB_ERR_MEMORY:
+ log_error(LOG_LEVEL_ERROR, "Out of memory while parsing request.");
+ break;
+ case JB_ERR_PARSE:
+ log_error(LOG_LEVEL_ERROR, "Couldn't parse request: %s.", req);
+ break;
+ }
+
freez(req);
break;
}
return;
}
+ /* grab the rest of the client's headers */
+ init_list(headers);
+ for (;;)
+ {
+ if ( ( ( p = get_header(csp) ) != NULL) && ( *p == '\0' ) )
+ {
+ len = read_socket(csp->cfd, buf, sizeof(buf));
+ if (len <= 0)
+ {
+ log_error(LOG_LEVEL_ERROR, "read from client failed: %E");
+ return;
+ }
+
+ /*
+ * If there is no memory left for buffering the
+ * request, there is nothing we can do but hang up
+ */
+ if (add_to_iob(csp, buf, len))
+ {
+ return;
+ }
+ continue;
+ }
+
+ if (p == NULL) break;
+
+ enlist(headers, p);
+ freez(p);
+
+ }
+
+ if (http->host == NULL)
+ {
+ /*
+ * Intercepted or invalid request without domain
+ * inside the request line. Try to get it another way.
+ */
+ if (JB_ERR_OK == get_destination_from_headers(headers, http))
+ {
+ /* Split the domain we just got for pattern matching */
+ init_domain_components(http);
+ }
+ else
+ {
+ /* We can't work without destination. Go spread the news.*/
+
+ req = list_to_text(headers);
+ chomp(req);
+ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, http->cmd);
+ log_error(LOG_LEVEL_ERROR,
+ "Privoxy was unable to get the destination for %s's request:\n%s\n%s",
+ csp->ip_addr_str, http->cmd, req);
+ freez(req);
+
+ strcpy(buf, MISSING_DESTINATION_RESPONSE);
+ write_socket(csp->cfd, buf, strlen(buf));
+ free_http_request(http);
+ destroy_list(headers);
+ return;
+ }
+ /*
+ * TODO: If available, use PF's ioctl DIOCNATLOOK as last resort
+ * to get the destination IP address, use it as host directly
+ * or do a reverse DNS lookup first.
+ */
+ }
+
/* decide how to route the HTTP request */
if ((fwd = forward_url(http, csp)) == NULL)
}
enlist(csp->headers, http->cmd);
+ /* Append the previously read headers */
+ list_append_list_unique(csp->headers, headers);
+ destroy_list(headers);
/*
* If the user has not supplied any wafers, and the user has not
jpeg_inspect = ((csp->action->flags & ACTION_JPEG_INSPECT) != 0);
- /* grab the rest of the client's headers */
-
- for (;;)
- {
- if ( ( ( p = get_header(csp) ) != NULL) && ( *p == '\0' ) )
- {
- len = read_socket(csp->cfd, buf, sizeof(buf));
- if (len <= 0)
- {
- log_error(LOG_LEVEL_ERROR, "read from client failed: %E");
- return;
- }
-
- /*
- * If there is no memory left for buffering the
- * request, there is nothing we can do but hang up
- */
- if (add_to_iob(csp, buf, len))
- {
- return;
- }
- continue;
- }
-
- if (p == NULL) break;
-
- enlist(csp->headers, p);
- freez(p);
- }
-
/*
* We have a request. Now, check to see if we need to
* intercept it, i.e. If ..
/* We may not forward the request by rfc2616 sect 14.31 */
(NULL != (rsp = direct_response(csp)))
- /* or a CGI call was detected and answered */
- || (NULL != (rsp = dispatch_cgi(csp)))
-
/* or we are enabled and... */
|| (IS_ENABLED_AND (
|| ( NULL != (rsp = trust_url(csp)))
#endif /* def FEATURE_TRUST */
- /* ..or a fast redirect kicked in */
-#ifdef FEATURE_FAST_REDIRECTS
- || (((csp->action->flags & ACTION_FAST_REDIRECTS) != 0) &&
- (NULL != (rsp = redirect_url(csp))))
-#endif /* def FEATURE_FAST_REDIRECTS */
+ /* ..or a redirect kicked in */
+ || ( NULL != (rsp = redirect_url(csp)))
))
- )
+
+ /*
+ * .. or a CGI call was detected and answered.
+ *
+ * This check comes last to give the user the power
+ * to deny acces to some (or all) of the cgi pages.
+ */
+ || (NULL != (rsp = dispatch_cgi(csp)))
+
+ )
{
/* Write the answer to the client */
if (write_socket(csp->cfd, rsp->head, rsp->head_length)
/* here we connect to the server, gateway, or the forwarder */
while ( (csp->sfd = forwarded_connect(fwd, http, csp))
- && (errno == EINVAL) && (socks_retries++ < 3))
+ && (errno == EINVAL) && (forwarded_connect_retries++ < max_forwarded_connect_retries))
{
- log_error(LOG_LEVEL_ERROR, "failed request #%u to connect to %s. Trying again.",
- socks_retries, http->hostport);
+ 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)
#if defined(unix)
- else if (strcmp(argv[argc_pos], "--no-daemon" ) == 0)
+ else if (strcmp(argv[argc_pos], "--no-daemon" ) == 0)
{
no_daemon = 1;
}
InitWin32();
#endif
-#if defined(OSX_DARWIN) || defined(__OpenBSD__)
+#ifdef FEATURE_PTHREAD
/*
* Prepare global mutex semaphores
*/
-#ifdef OSX_DARWIN
+ pthread_mutex_init(&log_mutex,0);
+ pthread_mutex_init(&log_init_mutex,0);
+
+#ifndef HAVE_GMTIME_R
pthread_mutex_init(&gmtime_mutex,0);
+#endif /* ndef HAVE_GMTIME_R */
+
+#ifndef HAVE_LOCALTIME_R
pthread_mutex_init(&localtime_mutex,0);
-#endif /* def OSX_DARWIN */
+#endif /* ndef HAVE_GMTIME_R */
+
+#ifndef HAVE_GETHOSTBYADDR_R
pthread_mutex_init(&gethostbyaddr_mutex,0);
- pthread_mutex_init(&gethostbyname_mutex,0);
-#endif /* defined(OSX_DARWIN) || defined(__OpenBSD__) */
+#endif /* ndef HAVE_GETHOSTBYADDR_R */
-#ifdef FEATURE_PTHREAD
- pthread_mutex_init(&log_mutex,0);
- pthread_mutex_init(&log_init_mutex,0);
+#ifndef HAVE_GETHOSTBYNAME_R
+ pthread_mutex_init(&gethostbyname_mutex,0);
+#endif /* ndef HAVE_GETHOSTBYNAME_R */
#endif /* FEATURE_PTHREAD */
#ifdef HAVE_RANDOM
#if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA)
{
int idx;
- const int catched_signals[] = { SIGABRT, SIGTERM, SIGINT, SIGHUP, 0 };
+ const int catched_signals[] = { SIGTERM, SIGINT, SIGHUP, 0 };
const int ignored_signals[] = { SIGPIPE, 0 };
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]);
}
* to the user and group ID indicated by the --user option
*/
write_pid_file();
-
+
if (NULL != pw)
{
if (setgid((NULL != grp) ? grp->gr_gid : pw->pw_gid))