X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=d73b4a99cba096cd335bf708a40e250a2e772989;hp=e21165bd480b6c0eae02c163207a53b94bc3db54;hb=a473a2a85dbf5325b270a906e85785ba4b032503;hpb=6936539c9dd5f94fcf6ee26303f680f829a19125 diff --git a/jcc.c b/jcc.c index e21165bd..d73b4a99 100644 --- a/jcc.c +++ b/jcc.c @@ -5,7 +5,7 @@ * Purpose : Main file. Contains main() method, main loop, and * the main connection-handling function. * - * Copyright : Written by and Copyright (C) 2001-2020 the + * Copyright : Written by and Copyright (C) 2001-2021 the * Privoxy team. https://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -559,8 +559,6 @@ static int client_has_unsupported_expectations(const struct client_state *csp) *********************************************************************/ static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers) { - char *req; - if (!(csp->config->feature_flags & RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS)) { log_error(LOG_LEVEL_ERROR, "%s's request: \'%s\' is invalid." @@ -587,15 +585,12 @@ static jb_err get_request_destination_elsewhere(struct client_state *csp, struct { /* We can't work without destination. Go spread the news.*/ - req = list_to_text(headers); - chomp(req); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, csp->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, csp->http->cmd, req); - freez(req); + "Privoxy was unable to get the destination for %s's request: %s", + csp->ip_addr_str, csp->http->cmd); write_socket_delayed(csp->cfd, MISSING_DESTINATION_RESPONSE, strlen(MISSING_DESTINATION_RESPONSE), get_write_delay(csp)); @@ -973,8 +968,8 @@ static int crunch_response_triggered(struct client_state *csp, const struct crun * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) - * 2 : fwd = The forwarding spec used for the request - * XXX: Should use http->fwd instead. + * 2 : fwd = The forwarding spec used for the request. + * Can be NULL. * 3 : request_line = The old request line which will be replaced. * * Returns : Nothing. Terminates in case of memory problems. @@ -1002,7 +997,7 @@ static void build_request_line(struct client_state *csp, const struct forward_sp *request_line = strdup(http->gpc); string_append(request_line, " "); - if (fwd->forward_host && fwd->type != FORWARD_WEBSERVER) + if (fwd != NULL && fwd->forward_host && fwd->type != FORWARD_WEBSERVER) { string_append(request_line, http->url); } @@ -1049,6 +1044,16 @@ static jb_err change_request_destination(struct client_state *csp) log_error(LOG_LEVEL_ERROR, "Couldn't parse rewritten request: %s.", jb_err_to_string(err)); } + if (http->ssl && strcmpic(csp->http->gpc, "CONNECT")) + { + /* + * A client header filter changed the request URL from + * http:// to https:// which we currently don't support. + */ + log_error(LOG_LEVEL_ERROR, "Changing the request destination from http " + "to https behind the client's back currently isn't supported."); + return JB_ERR_PARSE; + } return err; } @@ -1176,6 +1181,22 @@ void save_connection_destination(jb_socket sfd, server_connection->gateway_host = NULL; } server_connection->gateway_port = fwd->gateway_port; + if (NULL != fwd->auth_username) + { + server_connection->auth_username = strdup_or_die(fwd->auth_username); + } + else + { + server_connection->auth_username = NULL; + } + if (NULL != fwd->auth_password) + { + server_connection->auth_password = strdup_or_die(fwd->auth_password); + } + else + { + server_connection->auth_password = NULL; + } if (NULL != fwd->forward_host) { @@ -1839,7 +1860,7 @@ static jb_err receive_client_request(struct client_state *csp) * elsewhere failed or Privoxy is configured * to only accept proxy requests. * - * An error response has already been send + * An error response has already been sent * and we're done here. */ return JB_ERR_PARSE; @@ -1960,7 +1981,7 @@ static jb_err parse_client_request(struct client_state *csp) strlen(MESSED_UP_REQUEST_RESPONSE), get_write_delay(csp)); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, - "%s - - [%T] \"Invalid request generated\" 500 0", csp->ip_addr_str); + "%s - - [%T] \"Invalid request generated\" 400 0", csp->ip_addr_str); log_error(LOG_LEVEL_ERROR, "Invalid request line after applying header filters."); free_http_request(http); @@ -1978,6 +1999,142 @@ static jb_err parse_client_request(struct client_state *csp) } +/********************************************************************* + * + * Function : read_http_request_body + * + * Description : Reads remaining request body from the client. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : 0 on success, anything else is an error. + * + *********************************************************************/ +static int read_http_request_body(struct client_state *csp) +{ + size_t to_read = csp->expected_client_content_length; + int len; + + assert(to_read != 0); + + /* check if all data has been already read */ + if (to_read <= (csp->client_iob->eod - csp->client_iob->cur)) + { + return 0; + } + + for (to_read -= (size_t)(csp->client_iob->eod - csp->client_iob->cur); + to_read > 0 && data_is_available(csp->cfd, csp->config->socket_timeout); + to_read -= (unsigned)len) + { + char buf[BUFFER_SIZE]; + size_t max_bytes_to_read = to_read < sizeof(buf) ? to_read : sizeof(buf); + + log_error(LOG_LEVEL_CONNECT, + "Waiting for up to %d bytes of request body from the client.", + max_bytes_to_read); + len = read_socket(csp->cfd, buf, (int)max_bytes_to_read); + if (len <= -1) + { + log_error(LOG_LEVEL_CONNECT, "Failed receiving request body from %s: %E", csp->ip_addr_str); + return 1; + } + if (add_to_iob(csp->client_iob, csp->config->buffer_limit, (char *)buf, len)) + { + return 1; + } + assert(to_read >= len); + } + + if (to_read != 0) + { + log_error(LOG_LEVEL_CONNECT, "Not enough request body has been read: expected %d more bytes", + csp->expected_client_content_length); + return 1; + } + log_error(LOG_LEVEL_CONNECT, "The last %d bytes of the request body have been read", + csp->expected_client_content_length); + return 0; +} + + +/********************************************************************* + * + * Function : update_client_headers + * + * Description : Updates the HTTP headers from the client request. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : new_content_length = new content length value to set + * + * Returns : 0 on success, anything else is an error. + * + *********************************************************************/ +static int update_client_headers(struct client_state *csp, size_t new_content_length) +{ + static const char content_length[] = "Content-Length:"; + int updated = 0; + struct list_entry *p; + +#ifndef FEATURE_HTTPS_INSPECTION + for (p = csp->headers->first; +#else + for (p = csp->http->client_ssl ? csp->https_headers->first : csp->headers->first; +#endif + !updated && (p != NULL); p = p->next) + { + /* Header crunch()ed in previous run? -> ignore */ + if (p->str == NULL) + { + continue; + } + + /* Does the current parser handle this header? */ + if (0 == strncmpic(p->str, content_length, sizeof(content_length) - 1)) + { + updated = (JB_ERR_OK == header_adjust_content_length((char **)&(p->str), new_content_length)); + if (!updated) + { + return 1; + } + } + } + + return !updated; +} + + +/********************************************************************* + * + * Function : can_filter_request_body + * + * Description : Checks if the current request body can be stored in + * the client_iob without hitting buffer limit. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : TRUE if the current request size do not exceed buffer limit + * FALSE otherwise. + * + *********************************************************************/ +static int can_filter_request_body(const struct client_state *csp) +{ + if (!can_add_to_iob(csp->client_iob, csp->config->buffer_limit, + csp->expected_client_content_length)) + { + log_error(LOG_LEVEL_INFO, + "Not filtering request body from %s: buffer limit %d will be exceeded " + "(content length %d)", csp->ip_addr_str, csp->config->buffer_limit, + csp->expected_client_content_length); + return FALSE; + } + return TRUE; +} + + /********************************************************************* * * Function : send_http_request @@ -1995,6 +2152,32 @@ static int send_http_request(struct client_state *csp) { char *hdr; int write_failure; + const char *to_send; + size_t to_send_len; + int filter_client_body = csp->expected_client_content_length != 0 && + client_body_filters_enabled(csp->action) && can_filter_request_body(csp); + + if (filter_client_body) + { + if (read_http_request_body(csp)) + { + return 1; + } + to_send_len = csp->expected_client_content_length; + to_send = execute_client_body_filters(csp, &to_send_len); + if (to_send == NULL) + { + /* just flush client_iob */ + filter_client_body = FALSE; + } + else if (to_send_len != csp->expected_client_content_length && + update_client_headers(csp, to_send_len)) + { + log_error(LOG_LEVEL_HEADER, "Error updating client headers"); + return 1; + } + csp->expected_client_content_length = 0; + } hdr = list_to_text(csp->headers); if (hdr == NULL) @@ -2015,26 +2198,100 @@ static int send_http_request(struct client_state *csp) { log_error(LOG_LEVEL_CONNECT, "Failed sending request headers to: %s: %E", csp->http->hostport); + return 1; + } + + if (filter_client_body) + { + write_failure = 0 != write_socket(csp->server_connection.sfd, to_send, to_send_len); + freez(to_send); + if (write_failure) + { + log_error(LOG_LEVEL_CONNECT, "Failed sending filtered request body to: %s: %E", + csp->http->hostport); + return 1; + } } - else if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) == 0) + + if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) == 0) && (flush_iob(csp->server_connection.sfd, csp->client_iob, 0) < 0)) { - write_failure = 1; log_error(LOG_LEVEL_CONNECT, "Failed sending request body to: %s: %E", csp->http->hostport); + return 1; + } + return 0; +} + + +#ifdef FEATURE_HTTPS_INSPECTION +/********************************************************************* + * + * Function : read_https_request_body + * + * Description : Reads remaining request body from the client. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : 0 on success, anything else is an error. + * + *********************************************************************/ +static int read_https_request_body(struct client_state *csp) +{ + size_t to_read = csp->expected_client_content_length; + int len; + + assert(to_read != 0); + + /* check if all data has been already read */ + if (to_read <= (csp->client_iob->eod - csp->client_iob->cur)) + { + return 0; + } + + for (to_read -= (size_t)(csp->client_iob->eod - csp->client_iob->cur); + to_read > 0 && (is_ssl_pending(&(csp->ssl_client_attr)) || + data_is_available(csp->cfd, csp->config->socket_timeout)); + to_read -= (unsigned)len) + { + unsigned char buf[BUFFER_SIZE]; + size_t max_bytes_to_read = to_read < sizeof(buf) ? to_read : sizeof(buf); + + log_error(LOG_LEVEL_CONNECT, + "Waiting for up to %d bytes of request body from the client.", + max_bytes_to_read); + len = ssl_recv_data(&(csp->ssl_client_attr), buf, + (unsigned)max_bytes_to_read); + if (len <= 0) + { + log_error(LOG_LEVEL_CONNECT, "Failed receiving request body from %s", csp->ip_addr_str); + return 1; + } + if (add_to_iob(csp->client_iob, csp->config->buffer_limit, (char *)buf, len)) + { + return 1; + } + assert(to_read >= len); } - return write_failure; + if (to_read != 0) + { + log_error(LOG_LEVEL_CONNECT, "Not enough request body has been read: expected %d more bytes", to_read); + return 1; + } + log_error(LOG_LEVEL_CONNECT, "The last %d bytes of the request body have been read", + csp->expected_client_content_length); + return 0; } -#ifdef FEATURE_HTTPS_INSPECTION /********************************************************************* * * Function : receive_and_send_encrypted_post_data * - * Description : Reads remaining POST data from the client and sends + * Description : Reads remaining request body from the client and sends * it to the server. * * Parameters : @@ -2059,7 +2316,7 @@ static int receive_and_send_encrypted_post_data(struct client_state *csp) max_bytes_to_read = (int)csp->expected_client_content_length; } log_error(LOG_LEVEL_CONNECT, - "Waiting for up to %d bytes of POST data from the client.", + "Waiting for up to %d bytes of request body from the client.", max_bytes_to_read); len = ssl_recv_data(&(csp->ssl_client_attr), buf, (unsigned)max_bytes_to_read); @@ -2072,7 +2329,7 @@ static int receive_and_send_encrypted_post_data(struct client_state *csp) /* XXX: Does this actually happen? */ break; } - log_error(LOG_LEVEL_CONNECT, "Forwarding %d bytes of encrypted POST data", + log_error(LOG_LEVEL_CONNECT, "Forwarding %d bytes of encrypted request body", len); len = ssl_send_data(&(csp->ssl_server_attr), buf, (size_t)len); if (len == -1) @@ -2093,7 +2350,7 @@ static int receive_and_send_encrypted_post_data(struct client_state *csp) } } - log_error(LOG_LEVEL_CONNECT, "Done forwarding encrypted POST data"); + log_error(LOG_LEVEL_CONNECT, "Done forwarding encrypted request body"); return 0; @@ -2118,6 +2375,32 @@ static int send_https_request(struct client_state *csp) char *hdr; int ret; long flushed = 0; + const char *to_send; + size_t to_send_len; + int filter_client_body = csp->expected_client_content_length != 0 && + client_body_filters_enabled(csp->action) && can_filter_request_body(csp); + + if (filter_client_body) + { + if (read_https_request_body(csp)) + { + return 1; + } + to_send_len = csp->expected_client_content_length; + to_send = execute_client_body_filters(csp, &to_send_len); + if (to_send == NULL) + { + /* just flush client_iob */ + filter_client_body = FALSE; + } + else if (to_send_len != csp->expected_client_content_length && + update_client_headers(csp, to_send_len)) + { + log_error(LOG_LEVEL_HEADER, "Error updating client headers"); + return 1; + } + csp->expected_client_content_length = 0; + } hdr = list_to_text(csp->https_headers); if (hdr == NULL) @@ -2144,6 +2427,18 @@ static int send_https_request(struct client_state *csp) return 1; } + if (filter_client_body) + { + ret = ssl_send_data(&(csp->ssl_server_attr), (const unsigned char *)to_send, to_send_len); + freez(to_send); + if (ret < 0) + { + log_error(LOG_LEVEL_CONNECT, "Failed sending filtered request body to: %s", + csp->http->hostport); + return 1; + } + } + if (((csp->flags & CSP_FLAG_PIPELINED_REQUEST_WAITING) == 0) && ((flushed = ssl_flush_socket(&(csp->ssl_server_attr), csp->client_iob)) < 0)) @@ -2152,7 +2447,7 @@ static int send_https_request(struct client_state *csp) csp->http->hostport); return 1; } - if (flushed != 0) + if (flushed != 0 || csp->expected_client_content_length != 0) { if (csp->expected_client_content_length != 0) { @@ -2243,6 +2538,107 @@ static jb_err receive_encrypted_request(struct client_state *csp) } +/********************************************************************* + * + * Function : change_encrypted_request_destination + * + * Description : Parse a (rewritten) request line from an encrypted + * request and regenerate the http request data. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : Forwards the parse_http_request() return code. + * Terminates in case of memory problems. + * + *********************************************************************/ +static jb_err change_encrypted_request_destination(struct client_state *csp) +{ + jb_err err; + char *original_host = csp->http->host; + int original_port = csp->http->port; + + log_error(LOG_LEVEL_REDIRECTS, "Rewrite detected: %s", + csp->https_headers->first->str); + csp->http->host = NULL; + free_http_request(csp->http); + err = parse_http_request(csp->https_headers->first->str, csp->http); + if (JB_ERR_OK != err) + { + log_error(LOG_LEVEL_ERROR, "Couldn't parse rewritten request: %s.", + jb_err_to_string(err)); + freez(original_host); + return err; + } + + if (csp->http->host == NULL) + { + char port_string[10]; + /* + * The rewritten request line did not specify a host + * which means we can use the original host specified + * by the client. + */ + csp->http->host = original_host; + csp->http->port = original_port; + log_error(LOG_LEVEL_REDIRECTS, "Keeping the original host: %s", + csp->http->host); + /* + * If the rewritten request line didn't contain a host + * it also didn't contain a port so we can reuse the host + * port. + */ + freez(csp->http->hostport); + csp->http->hostport = strdup_or_die(csp->http->host); + snprintf(port_string, sizeof(port_string), ":%d", original_port); + err = string_append(&csp->http->hostport, port_string); + if (err != JB_ERR_OK) + { + log_error(LOG_LEVEL_ERROR, "Failed to rebuild hostport: %s.", + jb_err_to_string(err)); + return err; + } + + /* + * While the request line didn't mention it, + * we're https-inspecting and want to speak TLS + * with the server. + */ + csp->http->server_ssl = 1; + csp->http->ssl = 1; + } + else + { + /* The rewrite filter added a host so we can ditch the original */ + freez(original_host); + csp->http->server_ssl = csp->http->ssl; + } + + csp->http->client_ssl = 1; + + freez(csp->https_headers->first->str); + build_request_line(csp, NULL, &csp->https_headers->first->str); + + if (!server_use_ssl(csp)) + { + log_error(LOG_LEVEL_REDIRECTS, + "Rewritten request line results in downgrade to http"); + /* + * Replace the unencryptd headers received with the + * CONNECT request with the ones we received securely. + */ + destroy_list(csp->headers); + csp->headers->first = csp->https_headers->first; + csp->headers->last = csp->https_headers->last; + csp->https_headers->first = NULL; + csp->https_headers->last = NULL; + } + + return JB_ERR_OK; + +} + + /********************************************************************* * * Function : process_encrypted_request @@ -2276,7 +2672,8 @@ static jb_err process_encrypted_request(struct client_state *csp) err = receive_encrypted_request(csp); if (err != JB_ERR_OK) { - if (csp->client_iob->cur == NULL) + if (csp->client_iob->cur == NULL || + csp->client_iob->cur == csp->client_iob->eod) { /* * We did not receive any data, most likely because the @@ -2423,6 +2820,22 @@ static jb_err process_encrypted_request(struct client_state *csp) return JB_ERR_PARSE; } + if ((NULL == csp->https_headers->first->str) + || (strcmp(csp->http->cmd, csp->https_headers->first->str) && + (JB_ERR_OK != change_encrypted_request_destination(csp)))) + { + ssl_send_data_delayed(&(csp->ssl_client_attr), + (const unsigned char *)MESSED_UP_REQUEST_RESPONSE, + strlen(MESSED_UP_REQUEST_RESPONSE), get_write_delay(csp)); + log_error(LOG_LEVEL_ERROR, + "Invalid request line after applying header filters."); + /* XXX: Use correct size */ + log_error(LOG_LEVEL_CLF, + "%s - - [%T] \"Invalid request generated\" 400 0", csp->ip_addr_str); + + return JB_ERR_PARSE; + } + log_error(LOG_LEVEL_HEADER, "Encrypted request processed"); log_applied_actions(csp->action); log_error(LOG_LEVEL_REQUEST, "https://%s%s", csp->http->hostport, @@ -2824,6 +3237,37 @@ static void handle_established_connection(struct client_state *csp) #ifdef FEATURE_HTTPS_INSPECTION if (client_use_ssl(csp)) { + if (csp->http->status == 101) + { + len = ssl_recv_data(&(csp->ssl_client_attr), + (unsigned char *)csp->receive_buffer, + (size_t)max_bytes_to_read); + if (len == -1) + { + log_error(LOG_LEVEL_ERROR, "Failed to receive data " + "on client socket %d for an upgraded connection", + csp->cfd); + break; + } + if (len == 0) + { + log_error(LOG_LEVEL_CONNECT, "Done receiving data " + "on client socket %d for an upgraded connection", + csp->cfd); + break; + } + byte_count += (unsigned long long)len; + len = ssl_send_data(&(csp->ssl_server_attr), + (unsigned char *)csp->receive_buffer, (size_t)len); + if (len == -1) + { + log_error(LOG_LEVEL_ERROR, "Failed to send data " + "on server socket %d for an upgraded connection", + csp->server_connection.sfd); + break; + } + continue; + } log_error(LOG_LEVEL_CONNECT, "Breaking with TLS/SSL."); break; } @@ -3677,7 +4121,7 @@ static void chat(struct client_state *csp) use_ssl_tunnel = 1; } - if (http->ssl && csp->action->flags & ACTION_IGNORE_CERTIFICATE_ERRORS) + if (http->ssl && (csp->action->flags & ACTION_IGNORE_CERTIFICATE_ERRORS)) { csp->dont_verify_certificate = 1; } @@ -3839,7 +4283,7 @@ static void chat(struct client_state *csp) } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ #ifdef FEATURE_HTTPS_INSPECTION - if (http->ssl && !use_ssl_tunnel) + if (client_use_ssl(csp) && !use_ssl_tunnel) { int ret; /* @@ -4102,10 +4546,12 @@ static void chat(struct client_state *csp) else { /* - * If server certificate is invalid, we must inform client and then - * close connection with client. + * If server certificate has been verified and is invalid, + * we must inform the client and then close the connection + * with client and server. */ - if (csp->server_cert_verification_result != SSL_CERT_VALID) + if (csp->server_cert_verification_result != SSL_CERT_VALID && + csp->server_cert_verification_result != SSL_CERT_NOT_VERIFIED) { ssl_send_certificate_error(csp); close_client_and_server_ssl_connections(csp); @@ -4253,7 +4699,7 @@ static void prepare_csp_for_next_request(struct client_state *csp) assert(bytes_to_shift > 0); assert(data_length > 0); - log_error(LOG_LEVEL_CONNECT, "Shifting %d pipelined bytes by %d bytes", + log_error(LOG_LEVEL_CONNECT, "Shifting %lu pipelined bytes by %ld bytes", data_length, bytes_to_shift); memmove(csp->client_iob->buf, csp->client_iob->cur, data_length); csp->client_iob->cur = csp->client_iob->buf; @@ -4487,6 +4933,20 @@ static void serve(struct client_state *csp) chat(csp); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + if (csp->cfd != JB_INVALID_SOCKET) + { + log_error(LOG_LEVEL_CONNECT, "Closing client socket %d. " + "Keep-alive: %u. Socket alive: %u. Data available: %u. " + "Configuration file change detected: %u. Requests received: %u.", + csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE), + socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0), + config_file_change_detected, csp->requests_received_total); +#ifdef FEATURE_HTTPS_INSPECTION + close_client_ssl_connection(csp); +#endif + drain_and_close_socket(csp->cfd); + } + if (csp->server_connection.sfd != JB_INVALID_SOCKET) { #ifdef FEATURE_CONNECTION_SHARING @@ -4507,20 +4967,6 @@ static void serve(struct client_state *csp) mark_connection_closed(&csp->server_connection); #endif - if (csp->cfd != JB_INVALID_SOCKET) - { - log_error(LOG_LEVEL_CONNECT, "Closing client socket %d. " - "Keep-alive: %u. Socket alive: %u. Data available: %u. " - "Configuration file change detected: %u. Requests received: %u.", - csp->cfd, 0 != (csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE), - socket_is_still_alive(csp->cfd), data_is_available(csp->cfd, 0), - config_file_change_detected, csp->requests_received_total); -#ifdef FEATURE_HTTPS_INSPECTION - close_client_ssl_connection(csp); -#endif - drain_and_close_socket(csp->cfd); - } - free_csp_resources(csp); csp->flags &= ~CSP_FLAG_ACTIVE; @@ -5137,7 +5583,10 @@ int main(int argc, char **argv) } #endif - chdir("/"); + if (chdir("/") != 0) + { + log_error(LOG_LEVEL_FATAL, "Failed to cd into '/': %E"); + } } /* -END- if (daemon_mode) */ @@ -5496,7 +5945,7 @@ static void listen_loop(void) csp = &csp_list->csp; log_error(LOG_LEVEL_CONNECT, - "Waiting for the next client connection. Currently active threads: %d", + "Waiting for the next client connection. Currently active threads: %u", active_threads); /* @@ -5713,7 +6162,7 @@ static void listen_loop(void) * XXX: If you assume ... */ log_error(LOG_LEVEL_ERROR, - "Unable to take any additional connections: %E. Active threads: %d", + "Unable to take any additional connections: %E. Active threads: %u", active_threads); write_socket_delayed(csp->cfd, TOO_MANY_CONNECTIONS_RESPONSE, strlen(TOO_MANY_CONNECTIONS_RESPONSE), get_write_delay(csp)); @@ -5740,7 +6189,7 @@ static void listen_loop(void) #ifdef FEATURE_GRACEFUL_TERMINATION - log_error(LOG_LEVEL_INFO, "Graceful termination requested"); + log_error(LOG_LEVEL_INFO, "Graceful termination requested."); unload_current_config_file(); unload_current_actions_file(); @@ -5770,6 +6219,8 @@ static void listen_loop(void) freez(basedir); #endif + log_error(LOG_LEVEL_INFO, "Exiting gracefully."); + #if defined(_WIN32) && !defined(_WIN_CONSOLE) /* Cleanup - remove taskbar icon etc. */ TermLogWindow();