X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=jcc.c;h=62f54ad912d2d0c26d0ac9be3df4ce08ae131f0f;hb=caa0ecb38edad98ac366edef498030784f19403e;hp=caee73a3a5b1ce16587a8805ae8e97cd0cf594d8;hpb=d06dfaa63787c7d7d796d9e8193b2668692d049b;p=privoxy.git diff --git a/jcc.c b/jcc.c index caee73a3..62f54ad9 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.131 2007/04/22 13:24:50 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.134 2007/05/16 14:59:46 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -33,6 +33,21 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.131 2007/04/22 13:24:50 fabiankeil Exp $" * * Revisions : * $Log: jcc.c,v $ + * Revision 1.134 2007/05/16 14:59:46 fabiankeil + * - Fix config file loading on Unix if no config file is specified. + * Since r1.97 Privoxy would always interpret the last argument as + * config file, even if it's a valid command line option. + * - Abort in case of unrecognized command line options. Closes #1719696. + * - Remove a bunch of unnecessary strcpy() calls (yay for c&p without thinking). + * - Replace the remaining strcpy() and strcat() calls with strlcpy() and strcat(). + * + * Revision 1.133 2007/05/04 11:23:19 fabiankeil + * - Don't rerun crunchers that only depend on the request URL. + * - Don't count redirects and CGI requests as "blocked requests". + * + * Revision 1.132 2007/04/25 15:15:17 fabiankeil + * Support crunching based on tags created by server-header taggers. + * * Revision 1.131 2007/04/22 13:24:50 fabiankeil * Make HTTP snippets static (again). Add a Content-Type for those * with content so the browser doesn't guess it based on the URL. @@ -1017,6 +1032,43 @@ const static char NULL_BYTE_RESPONSE[] = "Connection: close\r\n\r\n" "Bad request. Null byte(s) before end of request.\r\n"; +/* A function to crunch a response */ +typedef struct http_response *(*crunch_func_ptr)(struct client_state *); + +/* Crunch function flags */ +#define CF_NO_FLAGS 0 +/* Cruncher applies to forced requests as well */ +#define CF_IGNORE_FORCE 1 +/* Crunched requests are counted for the block statistics */ +#define CF_COUNT_AS_REJECT 2 + +/* A crunch function and its flags */ +struct cruncher +{ + const crunch_func_ptr cruncher; + const int flags; +}; + +/* Complete list of cruncher functions */ +const static struct cruncher crunchers_all[] = { + { direct_response, CF_COUNT_AS_REJECT|CF_IGNORE_FORCE}, + { block_url, CF_COUNT_AS_REJECT }, +#ifdef FEATURE_TRUST + { trust_url, CF_COUNT_AS_REJECT }, +#endif /* def FEATURE_TRUST */ + { redirect_url, CF_NO_FLAGS }, + { dispatch_cgi, CF_IGNORE_FORCE}, + { NULL, 0 } +}; + +/* Light version, used after tags are applied */ +const static struct cruncher crunchers_light[] = { + { block_url, CF_COUNT_AS_REJECT }, + { redirect_url, CF_NO_FLAGS }, + { NULL, 0 } +}; + + #if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA) /********************************************************************* * @@ -1103,13 +1155,13 @@ int client_protocol_is_unsupported(const struct client_state *csp, char *req) { if (!strncmpic(req, "GET ftp://", 10)) { - strcpy(buf, FTP_RESPONSE); + strlcpy(buf, FTP_RESPONSE, sizeof(buf)); log_error(LOG_LEVEL_ERROR, "%s tried to use Privoxy as FTP proxy: %s", csp->ip_addr_str, req); } else { - strcpy(buf, GOPHER_RESPONSE); + strlcpy(buf, GOPHER_RESPONSE, sizeof(buf)); log_error(LOG_LEVEL_ERROR, "%s tried to use Privoxy as gopher proxy: %s", csp->ip_addr_str, req); } @@ -1153,7 +1205,6 @@ int client_protocol_is_unsupported(const struct client_state *csp, char *req) *********************************************************************/ jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers) { - char buf[BUFFER_SIZE]; char *req; if (!(csp->config->feature_flags & RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS)) @@ -1165,8 +1216,7 @@ jb_err get_request_destination_elsewhere(struct client_state *csp, struct list * log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, csp->http->cmd); - strcpy(buf, CHEADER); - write_socket(csp->cfd, buf, strlen(buf)); + write_socket(csp->cfd, CHEADER, strlen(CHEADER)); destroy_list(headers); return JB_ERR_PARSE; @@ -1192,8 +1242,7 @@ jb_err get_request_destination_elsewhere(struct client_state *csp, struct list * csp->ip_addr_str, csp->http->cmd, req); freez(req); - strcpy(buf, MISSING_DESTINATION_RESPONSE); - write_socket(csp->cfd, buf, strlen(buf)); + write_socket(csp->cfd, MISSING_DESTINATION_RESPONSE, strlen(MISSING_DESTINATION_RESPONSE)); destroy_list(headers); return JB_ERR_PARSE; @@ -1479,8 +1528,7 @@ int request_contains_null_bytes(const struct client_state *csp, char *buf, int l log_error(LOG_LEVEL_HEADER, "Offending request data with NULL bytes turned into \'°\' characters: %s", buf); - strcpy(buf, NULL_BYTE_RESPONSE); - write_socket(csp->cfd, buf, strlen(buf)); + write_socket(csp->cfd, NULL_BYTE_RESPONSE, strlen(NULL_BYTE_RESPONSE)); /* XXX: Log correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request\" 400 0", csp->ip_addr_str); @@ -1501,69 +1549,43 @@ int request_contains_null_bytes(const struct client_state *csp, char *buf, int l * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : crunchers = list of cruncher functions to run * * Returns : TRUE if the request was answered with a crunch response * FALSE otherwise. * *********************************************************************/ -int crunch_response_triggered(struct client_state *csp) +int crunch_response_triggered(struct client_state *csp, const struct cruncher crunchers[]) { -/* - * This next lines are a little ugly, but they simplify the if statements - * below. Basically if TOGGLE, then we want the if to test if the - * CSP_FLAG_TOGGLED_ON flag ist set, else we don't. And if FEATURE_FORCE_LOAD, - * then we want the if to test for CSP_FLAG_FORCED, else we don't. - */ -#ifdef FEATURE_TOGGLE -# define IS_TOGGLED_ON_AND (csp->flags & CSP_FLAG_TOGGLED_ON) && -#else /* ifndef FEATURE_TOGGLE */ -# define IS_TOGGLED_ON_AND -#endif /* ndef FEATURE_TOGGLE */ -#ifdef FEATURE_FORCE_LOAD -# define IS_NOT_FORCED_AND !(csp->flags & CSP_FLAG_FORCED) && -#else /* ifndef FEATURE_FORCE_LOAD */ -# define IS_NOT_FORCED_AND -#endif /* def FEATURE_FORCE_LOAD */ - -#define IS_ENABLED_AND IS_TOGGLED_ON_AND IS_NOT_FORCED_AND - struct http_response *rsp = NULL; + const struct cruncher *c; - if ( - /* We may not forward the request by rfc2616 sect 14.31 */ - (NULL != (rsp = direct_response(csp))) - - /* or we are enabled and... */ - || (IS_ENABLED_AND ( - - /* ..the request was blocked */ - ( NULL != (rsp = block_url(csp))) - - /* ..or untrusted */ -#ifdef FEATURE_TRUST - || ( NULL != (rsp = trust_url(csp))) -#endif /* def FEATURE_TRUST */ - - /* ..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))) - - ) + for (c = crunchers; c->cruncher != NULL; c++) { - /* Deliver, log and free the interception response. */ - send_crunch_response(csp, rsp); + /* + * Check the cruncher if either Privoxy is toggled + * on and the request isn't forced, or if the cruncher + * applies to forced requests as well. + */ + if (((csp->flags & CSP_FLAG_TOGGLED_ON) && + !(csp->flags & CSP_FLAG_FORCED)) || + (c->flags & CF_IGNORE_FORCE)) + { + rsp = c->cruncher(csp); + if (NULL != rsp) + { + /* Deliver, log and free the interception response. */ + send_crunch_response(csp, rsp); #ifdef FEATURE_STATISTICS - csp->flags |= CSP_FLAG_REJECTED; + if (c->flags & CF_COUNT_AS_REJECT) + { + csp->flags |= CSP_FLAG_REJECTED; + } #endif /* def FEATURE_STATISTICS */ - return TRUE; + return TRUE; + } + } } return FALSE; @@ -1703,7 +1725,7 @@ static void chat(struct client_state *csp) for (;;) { - len = read_socket(csp->cfd, buf, sizeof(buf)-1); + len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) break; /* error! */ @@ -1783,8 +1805,7 @@ static void chat(struct client_state *csp) if (http->cmd == NULL) { - strcpy(buf, CHEADER); - write_socket(csp->cfd, buf, strlen(buf)); + write_socket(csp->cfd, CHEADER, strlen(CHEADER)); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request\" 400 0", csp->ip_addr_str); log_error(LOG_LEVEL_ERROR, "Invalid header received from %s.", csp->ip_addr_str); @@ -1799,7 +1820,7 @@ static void chat(struct client_state *csp) { if ( ( ( p = get_header(csp) ) != NULL) && ( *p == '\0' ) ) { - len = read_socket(csp->cfd, buf, sizeof(buf)); + len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) { log_error(LOG_LEVEL_ERROR, "read from client failed: %E"); @@ -1929,8 +1950,7 @@ static void chat(struct client_state *csp) } else { - strcpy(buf, CFORBIDDEN); - write_socket(csp->cfd, buf, strlen(buf)); + write_socket(csp->cfd, CFORBIDDEN, strlen(CFORBIDDEN)); 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; @@ -1994,7 +2014,7 @@ static void chat(struct client_state *csp) /* * We have a request. Check if one of the crunchers wants it. */ - if (crunch_response_triggered(csp)) + if (crunch_response_triggered(csp, crunchers_all)) { /* * Yes. The client got the crunch response @@ -2057,7 +2077,7 @@ static void chat(struct client_state *csp) /* Write the answer to the client */ - if(rsp != NULL) + if (rsp != NULL) { send_crunch_response(csp, rsp); } @@ -2096,7 +2116,7 @@ static void chat(struct client_state *csp) * so just send the "connect succeeded" message to the * client, flush the rest, and get out of the way. */ - if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1)) + if (write_socket(csp->cfd, CSUCCEED, strlen(CSUCCEED))) { freez(hdr); return; @@ -2145,7 +2165,7 @@ static void chat(struct client_state *csp) if (FD_ISSET(csp->cfd, &rfds)) { - len = read_socket(csp->cfd, buf, sizeof(buf)); + len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) { @@ -2263,7 +2283,7 @@ static void chat(struct client_state *csp) * Shouldn't happen because this was the second sed run * and tags are only created for the first one. */ - assert(!crunch_response_triggered(csp)); + assert(!crunch_response_triggered(csp, crunchers_all)); if (write_socket(csp->cfd, hdr, strlen(hdr)) || write_socket(csp->cfd, p != NULL ? p : csp->iob->cur, csp->content_length)) @@ -2332,7 +2352,7 @@ static void chat(struct client_state *csp) return; } - if (crunch_response_triggered(csp)) + if (crunch_response_triggered(csp, crunchers_light)) { /* * One of the tags created by a server-header @@ -2424,8 +2444,7 @@ static void chat(struct client_state *csp) { log_error(LOG_LEVEL_ERROR, "Empty server or forwarder response."); log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); - strcpy(buf, NO_SERVER_DATA_RESPONSE); - write_socket(csp->cfd, buf, strlen(buf)); + write_socket(csp->cfd, NO_SERVER_DATA_RESPONSE, strlen(NO_SERVER_DATA_RESPONSE)); free_http_request(http); return; } @@ -2441,7 +2460,7 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header"); } - if (crunch_response_triggered(csp)) + if (crunch_response_triggered(csp, crunchers_light)) { /* * One of the tags created by a server-header @@ -2626,13 +2645,17 @@ static int32 server_thread(void *data) void usage(const char *myname) { printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n" -#if !defined(unix) - "Usage: %s [--help] [--version] [configfile]\n" -#else - "Usage: %s [--help] [--version] [--no-daemon] [--pidfile pidfile] [--user user[.group]] [configfile]\n" -#endif - "Aborting.\n", myname); - + "Usage: %s " +#if defined(unix) + "[--chroot] " +#endif /* defined(unix) */ + "[--help] " +#if defined(unix) + "[--no-daemon] [--pidfile pidfile] [--user user[.group]] " +#endif /* defined(unix) */ + "[--version] [configfile]\n" + "Aborting\n", myname); + exit(2); } @@ -2756,6 +2779,9 @@ int main(int argc, const char *argv[]) /* * Parse the command line arguments + * + * XXX: simply printing usage information in case of + * invalid arguments isn't particular user friendly. */ while (++argc_pos < argc) { @@ -2836,8 +2862,19 @@ int main(int argc, const char *argv[]) { do_chroot = 1; } - #endif /* defined(unix) */ + + else if (argc_pos + 1 != argc) + { + /* + * This is neither the last command line + * option, nor was it recognized before, + * therefore it must be invalid. + */ + usage(argv[0]); + } + else + #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */ { configfile = argv[argc_pos]; @@ -2848,24 +2885,30 @@ int main(int argc, const char *argv[]) #if defined(unix) if ( *configfile != '/' ) { - char *abs_file, cwd[1024]; + char cwd[BUFFER_SIZE]; + char *abs_file; + size_t abs_file_size; /* make config-filename absolute here */ - if ( !(getcwd(cwd, sizeof(cwd)))) + if (NULL == getcwd(cwd, sizeof(cwd))) { - perror("get working dir failed"); + perror("failed to get current working directory"); exit( 1 ); } - if (!(basedir = strdup(cwd)) - || (!(abs_file = malloc( strlen( basedir ) + strlen( configfile ) + 5 )))) + /* XXX: why + 5? */ + abs_file_size = strlen(cwd) + strlen(configfile) + 5; + basedir = strdup(cwd); + + if (NULL == basedir || + NULL == (abs_file = malloc(abs_file_size))) { perror("malloc failed"); exit( 1 ); } - strcpy( abs_file, basedir ); - strcat( abs_file, "/" ); - strcat( abs_file, configfile ); + strlcpy(abs_file, basedir, abs_file_size); + strlcat(abs_file, "/", abs_file_size ); + strlcat(abs_file, configfile, abs_file_size); configfile = abs_file; } #endif /* defined unix */ @@ -3040,13 +3083,13 @@ int main(int argc, const char *argv[]) { char putenv_dummy[64]; - strcpy(putenv_dummy, "HOME=/"); + strlcpy(putenv_dummy, "HOME=/", sizeof(putenv_dummy)); if (putenv(putenv_dummy) != 0) { log_error(LOG_LEVEL_FATAL, "Cannot putenv(): HOME"); } - snprintf(putenv_dummy, 64, "USER=%s", pw->pw_name); + snprintf(putenv_dummy, sizeof(putenv_dummy), "USER=%s", pw->pw_name); if (putenv(putenv_dummy) != 0) { log_error(LOG_LEVEL_FATAL, "Cannot putenv(): USER");