diff --git a/mongoose.c b/mongoose.c index 38c3f684..d7e4d6ad 100644 --- a/mongoose.c +++ b/mongoose.c @@ -429,7 +429,7 @@ struct socket { enum { CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER, PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, - ACCESS_LOG_FILE, SSL_CHAIN_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE, + ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE, GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, @@ -445,7 +445,6 @@ static const char *config_options[] = { "R", "authentication_domain", "mydomain.com", "S", "ssi_pattern", "**.shtml$|**.shtm$", "a", "access_log_file", NULL, - "c", "ssl_chain_file", NULL, "d", "enable_directory_listing", "yes", "e", "error_log_file", NULL, "g", "global_passwords_file", NULL, @@ -597,10 +596,9 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) { // Return fake connection structure. Used for logging, if connection // is not applicable at the moment of logging. -static struct mg_connection *fc(void) { - static struct mg_context fake_context; +static struct mg_connection *fc(struct mg_context *ctx) { static struct mg_connection fake_connection; - fake_connection.ctx = &fake_context; + fake_connection.ctx = ctx; return &fake_connection; } @@ -2141,7 +2139,7 @@ static FILE *open_auth_file(struct mg_connection *conn, const char *path) { // Use global passwords file fp = mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r"); if (fp == NULL) - cry(fc(), "fopen(%s): %s", + cry(fc(ctx), "fopen(%s): %s", ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO)); } else if (!mg_stat(path, &st) && st.is_directory) { (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s", @@ -3131,7 +3129,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog) { // Do not send anything back to client, until we buffer in all // HTTP headers. data_len = 0; - headers_len = read_request(out, fc(), buf, sizeof(buf), &data_len); + headers_len = read_request(out, conn, buf, sizeof(buf), &data_len); if (headers_len <= 0) { send_http_error(conn, 500, http_500_error, "CGI program sent malformed or too big (>%u bytes) " @@ -3610,12 +3608,12 @@ static int set_ports_option(struct mg_context *ctx) { while (success && (list = next_option(list, &vec, NULL)) != NULL) { if (!parse_port_string(&vec, &so)) { - cry(fc(), "%s: %.*s: invalid port spec. Expecting list of: %s", + cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s", __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|p]"); success = 0; } else if (so.is_ssl && (ctx->ssl_ctx == NULL || ctx->config[SSL_CERTIFICATE] == NULL)) { - cry(fc(), "Cannot add SSL socket, is -ssl_certificate option set?"); + cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?"); success = 0; } else if ((sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6)) == INVALID_SOCKET || @@ -3637,14 +3635,14 @@ static int set_ports_option(struct mg_context *ctx) { bind(sock, &so.lsa.sa, sizeof(so.lsa)) != 0 || listen(sock, SOMAXCONN) != 0) { closesocket(sock); - cry(fc(), "%s: cannot bind to %.*s: %s", __func__, + cry(fc(ctx), "%s: cannot bind to %.*s: %s", __func__, vec.len, vec.ptr, strerror(ERRNO)); success = 0; } else if ((listener = (struct socket *) calloc(1, sizeof(*listener))) == NULL) { // NOTE(lsm): order is important: call cry before closesocket(), // cause closesocket() alters the errno. - cry(fc(), "%s: %s", __func__, strerror(ERRNO)); + cry(fc(ctx), "%s: %s", __func__, strerror(ERRNO)); closesocket(sock); success = 0; } else { @@ -3732,18 +3730,18 @@ static int check_acl(struct mg_context *ctx, const union usa *usa) { mask = 32; if (sscanf(vec.ptr, "%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n) != 5) { - cry(fc(), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__); + cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__); return -1; } else if (flag != '+' && flag != '-') { - cry(fc(), "%s: flag must be + or -: [%s]", __func__, vec.ptr); + cry(fc(ctx), "%s: flag must be + or -: [%s]", __func__, vec.ptr); return -1; } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) { - cry(fc(), "%s: bad ip address: [%s]", __func__, vec.ptr); + cry(fc(ctx), "%s: bad ip address: [%s]", __func__, vec.ptr); return -1; } else if (sscanf(vec.ptr + n, "/%d", &mask) == 0) { // Do nothing, no mask specified } else if (mask < 0 || mask > 32) { - cry(fc(), "%s: bad subnet mask: %d [%s]", __func__, n, vec.ptr); + cry(fc(ctx), "%s: bad subnet mask: %d [%s]", __func__, n, vec.ptr); return -1; } @@ -3775,11 +3773,11 @@ static int set_uid_option(struct mg_context *ctx) { success = 1; } else { if ((pw = getpwnam(uid)) == NULL) { - cry(fc(), "%s: unknown user [%s]", __func__, uid); + cry(fc(ctx), "%s: unknown user [%s]", __func__, uid); } else if (setgid(pw->pw_gid) == -1) { - cry(fc(), "%s: setgid(%s): %s", __func__, uid, strerror(errno)); + cry(fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno)); } else if (setuid(pw->pw_uid) == -1) { - cry(fc(), "%s: setuid(%s): %s", __func__, uid, strerror(errno)); + cry(fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno)); } else { success = 1; } @@ -3816,13 +3814,14 @@ static unsigned long ssl_id_callback(void) { } #if !defined(NO_SSL_DL) -static int load_dll(const char *dll_name, struct ssl_func *sw) { +static int load_dll(struct mg_context *ctx, const char *dll_name, + struct ssl_func *sw) { union {void *p; void (*fp)(void);} u; void *dll_handle; struct ssl_func *fp; if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) { - cry(fc(), "%s: cannot load %s", __func__, dll_name); + cry(fc(ctx), "%s: cannot load %s", __func__, dll_name); return 0; } @@ -3836,7 +3835,7 @@ static int load_dll(const char *dll_name, struct ssl_func *sw) { u.p = dlsym(dll_handle, fp->name); #endif // _WIN32 if (u.fp == NULL) { - cry(fc(), "%s: %s: cannot find %s", __func__, dll_name, fp->name); + cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name); return 0; } else { fp->ptr = u.fp; @@ -3849,13 +3848,13 @@ static int load_dll(const char *dll_name, struct ssl_func *sw) { // Dynamically load SSL library. Set up ctx->ssl_ctx pointer. static int set_ssl_option(struct mg_context *ctx) { - struct mg_request_info request_info; + static struct mg_request_info fake_request_info; int i, size; const char *pem = ctx->config[SSL_CERTIFICATE]; - const char *chain = ctx->config[SSL_CHAIN_FILE]; #if !defined(NO_SSL_DL) - if (!load_dll(SSL_LIB, ssl_sw) || !load_dll(CRYPTO_LIB, crypto_sw)) { + if (!load_dll(ctx, SSL_LIB, ssl_sw) || + !load_dll(ctx, CRYPTO_LIB, crypto_sw)) { return 0; } #endif // NO_SSL_DL @@ -3865,38 +3864,32 @@ static int set_ssl_option(struct mg_context *ctx) { SSL_load_error_strings(); if ((ctx->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { - cry(fc(), "SSL_CTX_new error: %s", ssl_error()); + cry(fc(ctx), "SSL_CTX_new (client) error: %s", ssl_error()); } if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) { - cry(fc(), "SSL_CTX_new error: %s", ssl_error()); - } else if (ctx->user_callback != NULL) { - memset(&request_info, 0, sizeof(request_info)); - request_info.user_data = ctx->user_data; + cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error()); + return 0; + } + + if (ctx->user_callback != NULL) { + fake_request_info.user_data = ctx->user_data; ctx->user_callback(MG_INIT_SSL, (struct mg_connection *) ctx->ssl_ctx); } - if (ctx->ssl_ctx != NULL && pem != NULL && - SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, SSL_FILETYPE_PEM) == 0) { - cry(fc(), "%s: cannot open %s: %s", __func__, pem, ssl_error()); - return 0; - } - if (ctx->ssl_ctx != NULL && pem != NULL && + if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, SSL_FILETYPE_PEM) == 0 || SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, SSL_FILETYPE_PEM) == 0) { - cry(fc(), "%s: cannot open %s: %s", __func__, pem, ssl_error()); - return 0; - } - if (ctx->ssl_ctx != NULL && chain != NULL && - SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, chain) == 0) { - cry(fc(), "%s: cannot open %s: %s", __func__, chain, ssl_error()); + cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error()); return 0; } + (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem); + // Initialize locking callbacks, needed for thread safety. // http://www.openssl.org/support/faq.html#PROG1 size = sizeof(pthread_mutex_t) * CRYPTO_num_locks(); if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) { - cry(fc(), "%s: cannot allocate mutexes: %s", __func__, ssl_error()); + cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error()); return 0; } @@ -3994,22 +3987,22 @@ struct mg_connection *mg_connect(struct mg_context *ctx, int sock; if (use_ssl && (ctx == NULL || ctx->client_ssl_ctx == NULL)) { - cry(fc(), "%s: SSL is not initialized", __func__); + cry(fc(ctx), "%s: SSL is not initialized", __func__); } else if ((he = gethostbyname(host)) == NULL) { - cry(fc(), "%s: gethostbyname(%s): %s", __func__, host, strerror(ERRNO)); + cry(fc(ctx), "%s: gethostbyname(%s): %s", __func__, host, strerror(ERRNO)); } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - cry(fc(), "%s: socket: %s", __func__, strerror(ERRNO)); + cry(fc(ctx), "%s: socket: %s", __func__, strerror(ERRNO)); } else { sin.sin_family = AF_INET; sin.sin_port = htons((uint16_t) port); sin.sin_addr = * (struct in_addr *) he->h_addr_list[0]; if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) { - cry(fc(), "%s: connect(%s:%d): %s", __func__, host, port, + cry(fc(ctx), "%s: connect(%s:%d): %s", __func__, host, port, strerror(ERRNO)); closesocket(sock); } else if ((newconn = (struct mg_connection *) calloc(1, sizeof(*newconn))) == NULL) { - cry(fc(), "%s: calloc: %s", __func__, strerror(ERRNO)); + cry(fc(ctx), "%s: calloc: %s", __func__, strerror(ERRNO)); closesocket(sock); } else { newconn->ctx = ctx; @@ -4036,29 +4029,29 @@ FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path, } else if (sscanf(url, "%9[htps]://%1024[^/]/%n", proto, host, &n) == 2) { port = mg_strcasecmp(proto, "https") == 0 ? 443 : 80; } else { - cry(fc(), "%s: invalid URL: [%s]", __func__, url); + cry(fc(ctx), "%s: invalid URL: [%s]", __func__, url); return NULL; } if ((newconn = mg_connect(ctx, host, port, !strcmp(proto, "https"))) == NULL) { - cry(fc(), "%s: mg_connect(%s): %s", __func__, url, strerror(ERRNO)); + cry(fc(ctx), "%s: mg_connect(%s): %s", __func__, url, strerror(ERRNO)); } else { mg_printf(newconn, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", url + n, host); data_length = 0; req_length = read_request(NULL, newconn, buf, buf_len, &data_length); if (req_length <= 0) { - cry(fc(), "%s(%s): invalid HTTP reply", __func__, url); + cry(fc(ctx), "%s(%s): invalid HTTP reply", __func__, url); } else if (parse_http_response(buf, req_length, ri) <= 0) { - cry(fc(), "%s(%s): cannot parse HTTP headers", __func__, url); + cry(fc(ctx), "%s(%s): cannot parse HTTP headers", __func__, url); } else if ((fp = fopen(path, "w+b")) == NULL) { - cry(fc(), "%s: fopen(%s): %s", __func__, path, strerror(ERRNO)); + cry(fc(ctx), "%s: fopen(%s): %s", __func__, path, strerror(ERRNO)); } else { // Write chunk of data that may be in the user's buffer data_length -= req_length; if (data_length > 0 && fwrite(buf + req_length, 1, data_length, fp) != (size_t) data_length) { - cry(fc(), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO)); + cry(fc(ctx), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO)); fclose(fp); fp = NULL; } @@ -4066,7 +4059,7 @@ FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path, // mg_read() cause we didn't set newconn->content_len properly. while (fp && (data_length = pull(0, newconn, buf2, sizeof(buf2))) > 0) { if (fwrite(buf2, 1, data_length, fp) != (size_t) data_length) { - cry(fc(), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO)); + cry(fc(ctx), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO)); fclose(fp); fp = NULL; break; @@ -4185,7 +4178,7 @@ static void worker_thread(struct mg_context *ctx) { conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE); if (conn == NULL) { - cry(fc(), "%s", "Cannot create new connection struct, OOM"); + cry(fc(ctx), "%s", "Cannot create new connection struct, OOM"); } else { conn->buf_size = MAX_REQUEST_SIZE; conn->buf = (char *) (conn + 1); @@ -4267,7 +4260,7 @@ static void accept_new_connection(const struct socket *listener, produce_socket(ctx, &accepted); } else { sockaddr_to_string(src_addr, sizeof(src_addr), &accepted.rsa); - cry(fc(), "%s: %s is not allowed to connect", __func__, src_addr); + cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr); (void) closesocket(accepted.sock); } } @@ -4411,16 +4404,16 @@ struct mg_context *mg_start(mg_callback_t user_callback, void *user_data, while (options && (name = *options++) != NULL) { if ((i = get_option_index(name)) == -1) { - cry(fc(), "Invalid option: %s", name); + cry(fc(ctx), "Invalid option: %s", name); free_context(ctx); return NULL; } else if ((value = *options++) == NULL) { - cry(fc(), "%s: option value cannot be NULL", name); + cry(fc(ctx), "%s: option value cannot be NULL", name); free_context(ctx); return NULL; } if (ctx->config[i] != NULL) { - cry(fc(), "warning: %s: duplicate option", name); + cry(fc(ctx), "warning: %s: duplicate option", name); } ctx->config[i] = mg_strdup(value); DEBUG_TRACE(("[%s] -> [%s]", name, value)); @@ -4471,7 +4464,7 @@ struct mg_context *mg_start(mg_callback_t user_callback, void *user_data, // Start worker threads for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) { if (mg_start_thread((mg_thread_func_t) worker_thread, ctx) != 0) { - cry(fc(), "Cannot start worker thread: %d", ERRNO); + cry(fc(ctx), "Cannot start worker thread: %d", ERRNO); } else { ctx->num_threads++; }