X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=jcc.c;h=62f54ad912d2d0c26d0ac9be3df4ce08ae131f0f;hb=caa0ecb38edad98ac366edef498030784f19403e;hp=b375b49ecefb0fa76eb50b98b76c3332dd8fdd74;hpb=66d5f733f047a1a177bfd1867ad53a933dd3ee7f;p=privoxy.git diff --git a/jcc.c b/jcc.c index b375b49e..62f54ad9 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.125 2007/03/09 14:12:00 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,42 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.125 2007/03/09 14:12:00 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. + * + * Revision 1.130 2007/04/19 13:47:34 fabiankeil + * Move crunching and request line rebuilding out of chat(). + * + * Revision 1.129 2007/04/15 16:39:20 fabiankeil + * Introduce tags as alternative way to specify which + * actions apply to a request. At the moment tags can be + * created based on client and server headers. + * + * Revision 1.128 2007/03/25 16:55:54 fabiankeil + * Don't CLF-log CONNECT requests twice. + * + * Revision 1.127 2007/03/20 13:53:17 fabiankeil + * Log the source address for ACL-related connection drops. + * + * Revision 1.126 2007/03/17 15:20:05 fabiankeil + * New config option: enforce-blocks. + * * Revision 1.125 2007/03/09 14:12:00 fabiankeil * - Move null byte check into separate function. * - Don't confuse the client with error pages @@ -942,53 +978,97 @@ static const char VANILLA_WAFER[] = "(copyright_or_otherwise)_applying_to_any_cookie._"; /* HTTP snipplets. */ -const char CSUCCEED[] = +const static char CSUCCEED[] = "HTTP/1.0 200 Connection established\n" "Proxy-Agent: Privoxy/" VERSION "\r\n\r\n"; -const char CHEADER[] = +const static char CHEADER[] = "HTTP/1.0 400 Invalid header received from browser\r\n" + "Proxy-Agent: Privoxy " VERSION "\r\n" + "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Invalid header received from browser.\r\n"; -const char CFORBIDDEN[] = +const static char CFORBIDDEN[] = "HTTP/1.0 403 Connection not allowable\r\n" "Proxy-Agent: Privoxy " VERSION "\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[] = +const static char FTP_RESPONSE[] = "HTTP/1.0 400 Invalid request received from browser\r\n" + "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Invalid request. Privoxy doesn't support FTP.\r\n"; -const char GOPHER_RESPONSE[] = +const static char GOPHER_RESPONSE[] = "HTTP/1.0 400 Invalid request received from browser\r\n" + "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Invalid request. Privoxy doesn't support gopher.\r\n"; /* XXX: should be a template */ -const char MISSING_DESTINATION_RESPONSE[] = +const static char MISSING_DESTINATION_RESPONSE[] = "HTTP/1.0 400 Bad request received from browser\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" + "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Bad request. Privoxy was unable to extract the destination.\r\n"; /* XXX: should be a template */ -const char NO_SERVER_DATA_RESPONSE[] = +const static char NO_SERVER_DATA_RESPONSE[] = "HTTP/1.0 502 Server or forwarder response empty\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" + "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Empty server or forwarder response.\r\n" "The connection was closed without sending any data.\r\n"; /* XXX: should be a template */ -const char NULL_BYTE_RESPONSE[] = +const static char NULL_BYTE_RESPONSE[] = "HTTP/1.0 400 Bad request received from browser\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" + "Content-Type: text/plain\r\n" "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) /********************************************************************* * @@ -1075,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); } @@ -1125,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)) @@ -1137,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; @@ -1164,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; @@ -1451,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); @@ -1464,6 +1540,125 @@ int request_contains_null_bytes(const struct client_state *csp, char *buf, int l } +/********************************************************************* + * + * Function : crunch_response_triggered + * + * Description : Checks if the request has to be crunched, + * and delivers the crunch response if necessary. + * + * 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, const struct cruncher crunchers[]) +{ + struct http_response *rsp = NULL; + const struct cruncher *c; + + for (c = crunchers; c->cruncher != NULL; c++) + { + /* + * 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 + if (c->flags & CF_COUNT_AS_REJECT) + { + csp->flags |= CSP_FLAG_REJECTED; + } +#endif /* def FEATURE_STATISTICS */ + + return TRUE; + } + } + } + + return FALSE; +} + + +/********************************************************************* + * + * Function : build_request_line + * + * Description : Builds the HTTP request line. + * + * If a HTTP forwarder is used it expects the whole URL, + * web servers only get the path. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : fwd = The forwarding spec used for the request + * + * Returns : Nothing. Terminates in case of memory problems. + * + *********************************************************************/ +void build_request_line(struct client_state *csp, const struct forward_spec *fwd) +{ + struct http_request *http = csp->http; + + assert(http->ssl == 0); + + /* + * Downgrade http version from 1.1 to 1.0 + * if +downgrade action applies. + */ + if ( (csp->action->flags & ACTION_DOWNGRADE) + && (!strcmpic(http->ver, "HTTP/1.1"))) + { + freez(http->ver); + http->ver = strdup("HTTP/1.0"); + + if (http->ver == NULL) + { + log_error(LOG_LEVEL_FATAL, "Out of memory downgrading HTTP version"); + } + } + + /* + * Rebuild the request line. + * XXX: If a http forwarder is used and the HTTP version + * wasn't downgraded, we don't have to rebuild anything. + */ + freez(http->cmd); + + http->cmd = strdup(http->gpc); + string_append(&http->cmd, " "); + + if (fwd->forward_host) + { + string_append(&http->cmd, http->url); + } + else + { + string_append(&http->cmd, http->path); + } + string_append(&http->cmd, " "); + string_append(&http->cmd, http->ver); + + if (http->cmd == NULL) + { + log_error(LOG_LEVEL_FATAL, "Out of memory writing HTTP command"); + } + log_error(LOG_LEVEL_HEADER, "New HTTP Request-Line: %s", http->cmd); +} + + /********************************************************************* * * Function : chat @@ -1480,35 +1675,11 @@ int request_contains_null_bytes(const struct client_state *csp, char *buf, int l * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * - * Returns : On success, the number of bytes written are returned (zero - * indicates nothing was written). On error, -1 is returned, - * and errno is set appropriately. If count is zero and the - * file descriptor refers to a regular file, 0 will be - * returned without causing any other effect. For a special - * file, the results are not portable. + * Returns : Nothing. * *********************************************************************/ static void chat(struct client_state *csp) { -/* - * This next lines are a little ugly, but they simplifies 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 - char buf[BUFFER_SIZE]; char *hdr; char *p; @@ -1554,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! */ @@ -1634,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); @@ -1650,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"); @@ -1680,7 +1850,7 @@ static void chat(struct client_state *csp) /* * If we still don't know the request destination, * the request is invalid or the client uses - * Privoxy without it's knowledge. + * Privoxy without its knowledge. */ if (JB_ERR_OK != get_request_destination_elsewhere(csp, headers)) { @@ -1780,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; @@ -1790,23 +1959,6 @@ static void chat(struct client_state *csp) } - /* - * Downgrade http version from 1.1 to 1.0 if +downgrade - * action applies - */ - if ( (http->ssl == 0) - && (!strcmpic(http->ver, "HTTP/1.1")) - && (csp->action->flags & ACTION_DOWNGRADE)) - { - freez(http->ver); - http->ver = strdup("HTTP/1.0"); - - if (http->ver == NULL) - { - log_error(LOG_LEVEL_FATAL, "Out of memory downgrading HTTP version"); - } - } - /* * Save a copy of the original request for logging */ @@ -1819,31 +1971,10 @@ static void chat(struct client_state *csp) /* * (Re)build the HTTP request for non-SSL requests. - * If forwarding, use the whole URL, else, use only the path. */ if (http->ssl == 0) { - freez(http->cmd); - - http->cmd = strdup(http->gpc); - string_append(&http->cmd, " "); - - if (fwd->forward_host) - { - string_append(&http->cmd, http->url); - } - else - { - string_append(&http->cmd, http->path); - } - string_append(&http->cmd, " "); - string_append(&http->cmd, http->ver); - - if (http->cmd == NULL) - { - log_error(LOG_LEVEL_FATAL, "Out of memory writing HTTP command"); - } - log_error(LOG_LEVEL_HEADER, "New HTTP Request-Line: %s", http->cmd); + build_request_line(csp, fwd); } enlist(csp->headers, http->cmd); @@ -1861,6 +1992,13 @@ static void chat(struct client_state *csp) enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER); } + hdr = sed(client_patterns, add_client_headers, csp); + if (hdr == NULL) + { + /* FIXME Should handle error properly */ + log_error(LOG_LEVEL_FATAL, "Out of memory parsing client header"); + } + csp->flags |= CSP_FLAG_CLIENT_HEADER_PARSING_DONE; #ifdef FEATURE_KILL_POPUPS block_popups = ((csp->action->flags & ACTION_NO_POPUPS) != 0); @@ -1874,59 +2012,28 @@ static void chat(struct client_state *csp) jpeg_inspect = ((csp->action->flags & ACTION_JPEG_INSPECT) != 0); /* - * We have a request. Now, check to see if we need to - * intercept it, i.e. If .. + * We have a request. Check if one of the crunchers wants it. */ - - 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))) - - ) + if (crunch_response_triggered(csp, crunchers_all)) { /* - * Deliver, log and free the interception - * response. Afterwards we're done here. + * Yes. The client got the crunch response + * and we are done here after cleaning up. */ - send_crunch_response(csp, rsp); -#ifdef FEATURE_STATISTICS - /* Count as a rejected request */ - csp->flags |= CSP_FLAG_REJECTED; -#endif /* def FEATURE_STATISTICS */ + freez(hdr); + list_remove_all(csp->headers); return; } - hdr = sed(client_patterns, add_client_headers, csp); - if (hdr == NULL) - { - /* FIXME Should handle error properly */ - log_error(LOG_LEVEL_FATAL, "Out of memory parsing client header"); - } - + /* + * The headers can't be removed earlier because + * they were still needed for the referrer check + * in case of CGI crunches. + * + * XXX: Would it be worth to move the referrer check + * into client_referrer() and set a flag if it's trusted? + */ list_remove_all(csp->headers); log_error(LOG_LEVEL_GPC, "%s%s", http->hostport, http->path); @@ -1970,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); } @@ -2009,10 +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. */ - log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 0", - csp->ip_addr_str, http->ocmd); - - if (write_socket(csp->cfd, CSUCCEED, sizeof(CSUCCEED)-1)) + if (write_socket(csp->cfd, CSUCCEED, strlen(CSUCCEED))) { freez(hdr); return; @@ -2061,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) { @@ -2175,6 +2279,12 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header"); } + /* + * Shouldn't happen because this was the second sed run + * and tags are only created for the first one. + */ + 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)) { @@ -2242,6 +2352,18 @@ static void chat(struct client_state *csp) return; } + if (crunch_response_triggered(csp, crunchers_light)) + { + /* + * One of the tags created by a server-header + * tagger triggered a crunch. We already + * delivered the crunch response to the client + * and are done here after cleaning up. + */ + freez(hdr); + return; + } + hdrlen = strlen(hdr); if (write_socket(csp->cfd, hdr, hdrlen) @@ -2322,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; } @@ -2339,6 +2460,17 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header"); } + if (crunch_response_triggered(csp, crunchers_light)) + { + /* + * One of the tags created by a server-header + * tagger triggered a crunch. We already + * delivered the crunch response to the client + * and are done here after cleaning up. + */ + freez(hdr); + return; + } #ifdef FEATURE_KILL_POPUPS /* Start blocking popups if appropriate. */ @@ -2513,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); } @@ -2643,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) { @@ -2723,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]; @@ -2735,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 */ @@ -2927,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"); @@ -3203,7 +3359,7 @@ static void listen_loop(void) #ifdef FEATURE_ACL if (block_acl(NULL,csp)) { - log_error(LOG_LEVEL_CONNECT, "Connection dropped due to ACL"); + log_error(LOG_LEVEL_CONNECT, "Connection from %s dropped due to ACL", csp->ip_addr_str); close_socket(csp->cfd); freez(csp); continue;