From a1acea24410bb0c143e5b09d864bfe978397ee0b Mon Sep 17 00:00:00 2001 From: DanyLE Date: Sun, 15 Jan 2023 18:21:42 +0100 Subject: [PATCH] Allow sandboxing plugin instances --- http_server.c | 71 ++--- httpd.c | 688 +++++++++++++++++++++++------------------------ lib/handle.c | 24 +- lib/handle.h | 18 +- lib/plugin.h | 9 +- plugin_manager.c | 309 ++++++++++++--------- 6 files changed, 563 insertions(+), 556 deletions(-) diff --git a/http_server.c b/http_server.c index 9e56936..a872087 100644 --- a/http_server.c +++ b/http_server.c @@ -76,11 +76,11 @@ void destroy_config() freedict(server_config.mimes); if (server_config.stat_fifo_path) free(server_config.stat_fifo_path); - if(server_config.plugins) + if (server_config.plugins) { for_each_assoc(it, server_config.plugins) { - freedict((dictionary_t) it->value); + freedict((dictionary_t)it->value); } freedict(server_config.plugins); } @@ -94,7 +94,7 @@ void destroy_config() { if (cnf->htdocs != NULL) free(cnf->htdocs); - if(cnf->plugins) + if (cnf->plugins) free(cnf->plugins); if (cnf->sock > 0) { @@ -114,7 +114,7 @@ static int config_handler(void *conf, const char *section, const char *name, config_t *pconfig = (config_t *)conf; regmatch_t regex_matches[2]; char buf[255]; - char * tmp; + char *tmp; struct stat st; // trim(section, ' '); // trim(value,' '); @@ -125,7 +125,7 @@ static int config_handler(void *conf, const char *section, const char *name, if (stat(value, &st) == -1) mkdirp(value, 0755); tmp = realpath(value, NULL); - if(!tmp) + if (!tmp) { ERROR("Unable to query real path for %s: %s", value, strerror(errno)); } @@ -148,7 +148,7 @@ static int config_handler(void *conf, const char *section, const char *name, if (stat(value, &st) == -1) mkdirp(value, 0700); tmp = realpath(value, NULL); - if(!tmp) + if (!tmp) { ERROR("Unable to query real path for %s: %s", value, strerror(errno)); } @@ -171,7 +171,7 @@ static int config_handler(void *conf, const char *section, const char *name, removeAll(value, 0); } tmp = realpath(value, NULL); - if(!tmp) + if (!tmp) { ERROR("Unable to query real path for %s: %s", value, strerror(errno)); } @@ -270,7 +270,7 @@ static int config_handler(void *conf, const char *section, const char *name, mkdirp(value, 0755); } p->htdocs = realpath(value, NULL); - if(!p->htdocs) + if (!p->htdocs) { ERROR("Unable to query real path for %s: %s", value, strerror(errno)); p->htdocs = strdup(value); @@ -280,7 +280,7 @@ static int config_handler(void *conf, const char *section, const char *name, LOG("Server root is %s", p->htdocs); } } - else if(strcmp(name, "plugins") == 0) + else if (strcmp(name, "plugins") == 0) { p->plugins = strdup(value); } @@ -320,34 +320,34 @@ static void init_plugins() { chain_t it, it2; dictionary_t config; - const char* value; + const char *value; for_each_assoc(it, server_config.plugins) { - config = (dictionary_t) it -> value; - if(config) + config = (dictionary_t)it->value; + if (config) { for_each_assoc(it2, config) { - LOG("Plugin %s: [%s] -> [%s]", it->key, it2->key, (char*) it2->value); - if(strncmp(it2->key, "file_type", 9) == 0 && it2->value) + LOG("Plugin %s: [%s] -> [%s]", it->key, it2->key, (char *)it2->value); + if (strncmp(it2->key, "file_type", 9) == 0 && it2->value) { - char* file_type = strdup((char*) it2->value); - char* token; + char *file_type = strdup((char *)it2->value); + char *token; char *stringp = file_type; - while((token = strsep(&stringp,","))) + while ((token = strsep(&stringp, ","))) { trim(token, ' '); - if(strlen(token) > 0) + if (strlen(token) > 0) { - dput(server_config.handlers,token, strdup((char*)it->key)); + dput(server_config.handlers, token, strdup((char *)it->key)); LOG("Plugin %s: support %s file", it->key, token); } } free(file_type); } } - value = (char*)dvalue(config,"autoload"); - if( value && (strncmp(value,"1", 1) == 0 || strncmp(value, "true", 3) == 0 ) ) + value = (char *)dvalue(config, "autoload"); + if (value && (strncmp(value, "1", 1) == 0 || strncmp(value, "true", 3) == 0)) { // load the plugin LOG("Plugin %s: autoloading...", it->key); @@ -532,8 +532,7 @@ void *resolve_request(void *data) char *rqp = NULL; char *oldrqp = NULL; rq->client->state = ANTD_CLIENT_RESOLVE_REQUEST; - htdocs(rq, path); - strcat(path, url); + snprintf(path, sizeof(path), "%s/%s", (char *)dvalue(rq->request, "SERVER_WWW_ROOT"), url); LOG("URL is : %s", url); LOG("Resource Path is : %s", path); // if (path[strlen(path) - 1] == '/') @@ -567,8 +566,7 @@ void *resolve_request(void *data) { newurl = __s("%s/index.%s", url, it->key); memset(path, 0, sizeof(path)); - htdocs(rq, path); - strcat(path, newurl); + snprintf(path, sizeof(path), "%s/%s", (char *)dvalue(rq->request, "SERVER_WWW_ROOT"), newurl); if (stat(path, &st) != 0) { free(newurl); @@ -669,7 +667,7 @@ int rule_check(const char *k, const char *v, const char *host, const char *_url, char *tmp, rep[10]; int idx = 0; memset(rep, 0, 10); - LOG("Verify %s=%s on %s or %s", k, v , url, host); + LOG("Verify %s=%s on %s or %s", k, v, url, host); // 1 group if (!host || !(ret = regex_match(k, host, 10, key_matches))) { @@ -863,11 +861,11 @@ char *apply_rules(dictionary_t rules, const char *host, char *url) for_each_assoc(it, rules) { k = it->key; - if(it->value) + if (it->value) { v = (char *)it->value; // 1 group - if (regex_match("$",v, 0, NULL)) + if (regex_match("$", v, 0, NULL)) { should_break = 1; } @@ -882,7 +880,7 @@ char *apply_rules(dictionary_t rules, const char *host, char *url) *query_string = '\0'; query_string++; } - if(should_break) + if (should_break) { i = rules->cap; LOG("Break rule check as matched found at %s -> %s", k, v); @@ -1718,7 +1716,7 @@ void *execute_plugin(void *data, const char *pname) port_config_t *pcnf = (port_config_t *)dvalue(server_config.ports, port_s); // check if plugin is enabled on this port - if(!pcnf->plugins || !regex_match(pattern, pcnf->plugins , 0,NULL)) + if (!pcnf->plugins || !regex_match(pattern, pcnf->plugins, 0, NULL)) { LOG("No plugin matched in [%s] using pattern [%s]", pcnf->plugins, pattern); antd_error(rq->client, 403, "Access forbidden"); @@ -1768,19 +1766,6 @@ dictionary_t mimes_list() return server_config.mimes; } -void dbdir(char **dest) -{ - *dest = server_config.db_path; -} -void tmpdir(char **dest) -{ - *dest = server_config.tmpdir; -} -void plugindir(char **dest) -{ - *dest =server_config.plugins_dir; -} - #ifdef USE_ZLIB int compressable(char *ctype) { diff --git a/httpd.c b/httpd.c index a9c7e84..70b0343 100644 --- a/httpd.c +++ b/httpd.c @@ -18,8 +18,8 @@ #include "lib/utils.h" #define SEND_STAT(fd, buff, ret, ...) \ - snprintf(buff, BUFFLEN, ##__VA_ARGS__); \ - ret = write(fd, buff, strlen(buff)); + snprintf(buff, BUFFLEN, ##__VA_ARGS__); \ + ret = write(fd, buff, strlen(buff)); static antd_scheduler_t *scheduler; @@ -33,104 +33,104 @@ static int ssl_session_ctx_id = 1; SSL_CTX *ctx; static void init_openssl() { - SSL_load_error_strings(); - OpenSSL_add_ssl_algorithms(); + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); } static SSL_CTX *create_context() { - const SSL_METHOD *method; - SSL_CTX *ctx; + const SSL_METHOD *method; + SSL_CTX *ctx; - method = SSLv23_server_method(); + method = SSLv23_server_method(); - ctx = SSL_CTX_new(method); - if (!ctx) - { - ERROR("Unable to create SSL context"); - ERR_print_errors_fp(stderr); - exit(EXIT_FAILURE); - } + ctx = SSL_CTX_new(method); + if (!ctx) + { + ERROR("Unable to create SSL context"); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } - return ctx; + return ctx; } #if OPENSSL_VERSION_NUMBER >= 0x10002000L static unsigned char antd_protocols[] = { - //TODO: add support to HTTP/2 protocol: 2,'h', '2', - 8, 'h', 't', 't', 'p', '/', '1', '.', '1'}; + // TODO: add support to HTTP/2 protocol: 2,'h', '2', + 8, 'h', 't', 't', 'p', '/', '1', '.', '1'}; static int alpn_advertise_protos_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) { - UNUSED(ssl); - UNUSED(arg); - *out = antd_protocols; - *outlen = sizeof(antd_protocols); - return SSL_TLSEXT_ERR_OK; + UNUSED(ssl); + UNUSED(arg); + *out = antd_protocols; + *outlen = sizeof(antd_protocols); + return SSL_TLSEXT_ERR_OK; } static int alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) { - UNUSED(ssl); - UNUSED(arg); - if (SSL_select_next_proto((unsigned char **)out, outlen, antd_protocols, sizeof(antd_protocols), in, inlen) == OPENSSL_NPN_NEGOTIATED) - { - return SSL_TLSEXT_ERR_OK; - } - else - { - ERROR("No protocol support overlap found between client and server\n"); - return SSL_TLSEXT_ERR_ALERT_FATAL; - } + UNUSED(ssl); + UNUSED(arg); + if (SSL_select_next_proto((unsigned char **)out, outlen, antd_protocols, sizeof(antd_protocols), in, inlen) == OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_OK; + } + else + { + ERROR("No protocol support overlap found between client and server\n"); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } } #endif static void configure_context(SSL_CTX *ctx) { #if defined(SSL_CTX_set_ecdh_auto) - SSL_CTX_set_ecdh_auto(ctx, 1); + SSL_CTX_set_ecdh_auto(ctx, 1); #else - SSL_CTX_set_tmp_ecdh(ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + SSL_CTX_set_tmp_ecdh(ctx, EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); #endif - //SSL_CTX_set_ecdh_auto(ctx, 1); - /* Set some options and the session id. + // SSL_CTX_set_ecdh_auto(ctx, 1); + /* Set some options and the session id. * SSL_OP_NO_SSLv2: SSLv2 is insecure, disable it. * SSL_OP_NO_TICKET: We don't want TLS tickets used because this is an SSL server caching example. * It should be fine to use tickets in addition to server side caching. */ - SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET); - SSL_CTX_set_session_id_context(ctx, (void *)&ssl_session_ctx_id, sizeof(ssl_session_ctx_id)); - // set the cipher suit - config_t *cnf = config(); - const char *suit = cnf->ssl_cipher ? cnf->ssl_cipher : CIPHER_SUIT; - LOG("Cirpher suit used: %s", suit); - if (SSL_CTX_set_cipher_list(ctx, suit) != 1) - { - ERROR("Fail to set ssl cirpher suit: %s", suit); - ERR_print_errors_fp(stderr); - exit(EXIT_FAILURE); - } - /* Set the key and cert */ - /* use the full chain bundle of certificate */ - //if (SSL_CTX_use_certificate_file(ctx, server_config->sslcert, SSL_FILETYPE_PEM) <= 0) { - if (SSL_CTX_use_certificate_chain_file(ctx, cnf->sslcert) <= 0) - { - ERROR("Fail to read SSL certificate chain file: %s", cnf->sslcert); - ERR_print_errors_fp(stderr); - exit(EXIT_FAILURE); - } + SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET); + SSL_CTX_set_session_id_context(ctx, (void *)&ssl_session_ctx_id, sizeof(ssl_session_ctx_id)); + // set the cipher suit + config_t *cnf = config(); + const char *suit = cnf->ssl_cipher ? cnf->ssl_cipher : CIPHER_SUIT; + LOG("Cirpher suit used: %s", suit); + if (SSL_CTX_set_cipher_list(ctx, suit) != 1) + { + ERROR("Fail to set ssl cirpher suit: %s", suit); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + /* Set the key and cert */ + /* use the full chain bundle of certificate */ + // if (SSL_CTX_use_certificate_file(ctx, server_config->sslcert, SSL_FILETYPE_PEM) <= 0) { + if (SSL_CTX_use_certificate_chain_file(ctx, cnf->sslcert) <= 0) + { + ERROR("Fail to read SSL certificate chain file: %s", cnf->sslcert); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } - if (SSL_CTX_use_PrivateKey_file(ctx, cnf->sslkey, SSL_FILETYPE_PEM) <= 0) - { - ERROR("Fail to read SSL private file: %s", cnf->sslkey); - ERR_print_errors_fp(stderr); - exit(EXIT_FAILURE); - } - if (!SSL_CTX_check_private_key(ctx)) - { - ERROR("Failed to validate SSL certificate"); - ERR_print_errors_fp(stderr); - exit(EXIT_FAILURE); - } + if (SSL_CTX_use_PrivateKey_file(ctx, cnf->sslkey, SSL_FILETYPE_PEM) <= 0) + { + ERROR("Fail to read SSL private file: %s", cnf->sslkey); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + if (!SSL_CTX_check_private_key(ctx)) + { + ERROR("Failed to validate SSL certificate"); + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } #if OPENSSL_VERSION_NUMBER >= 0x10002000L - SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, NULL); - SSL_CTX_set_next_protos_advertised_cb(ctx, alpn_advertise_protos_cb, NULL); + SSL_CTX_set_alpn_select_cb(ctx, alpn_select_cb, NULL); + SSL_CTX_set_next_protos_advertised_cb(ctx, alpn_advertise_protos_cb, NULL); #endif } @@ -138,314 +138,314 @@ static void configure_context(SSL_CTX *ctx) static void stop_serve(int dummy) { - UNUSED(dummy); - // close log server - closelog(); - sigset_t mask; - sigemptyset(&mask); - //Blocks the SIG_IGN signal (by adding SIG_IGN to newMask) - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGPIPE); - sigaddset(&mask, SIGABRT); - sigprocmask(SIG_BLOCK, &mask, NULL); - antd_scheduler_destroy(scheduler); - unload_all_plugin(); + UNUSED(dummy); + // close log server + closelog(); + sigset_t mask; + sigemptyset(&mask); + // Blocks the SIG_IGN signal (by adding SIG_IGN to newMask) + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGPIPE); + sigaddset(&mask, SIGABRT); + sigprocmask(SIG_BLOCK, &mask, NULL); + antd_scheduler_destroy(scheduler); + unload_all_plugin(); #ifdef USE_OPENSSL - FIPS_mode_set(0); - SSL_CTX_free(ctx); - FIPS_mode_set(0); - // DEPRECATED: CONF_modules_unload(1); - EVP_cleanup(); - EVP_PBE_cleanup(); - // DEPRECATED:ENGINE_cleanup(); - CRYPTO_cleanup_all_ex_data(); - // DEPRECATED: ERR_remove_state(0); - ERR_free_strings(); + FIPS_mode_set(0); + SSL_CTX_free(ctx); + FIPS_mode_set(0); + // DEPRECATED: CONF_modules_unload(1); + EVP_cleanup(); + EVP_PBE_cleanup(); + // DEPRECATED:ENGINE_cleanup(); + CRYPTO_cleanup_all_ex_data(); + // DEPRECATED: ERR_remove_state(0); + ERR_free_strings(); #endif - destroy_config(); - sigprocmask(SIG_UNBLOCK, &mask, NULL); + destroy_config(); + sigprocmask(SIG_UNBLOCK, &mask, NULL); } static void antd_monitor(port_config_t *pcnf) { - antd_task_t *task = NULL; - int client_sock = -1; - struct sockaddr_in client_name; - socklen_t client_name_len = sizeof(client_name); - char *client_ip = NULL; - config_t *conf = config(); - if (pcnf->sock > 0) - { - client_sock = accept(pcnf->sock, (struct sockaddr *)&client_name, &client_name_len); - if (client_sock > 0) - { - // just dump the scheduler when we have a connection - antd_client_t *client = (antd_client_t *)malloc(sizeof(antd_client_t)); - antd_request_t *request = (antd_request_t *)malloc(sizeof(*request)); - request->client = client; - request->request = dict(); - client->zstream = NULL; - client->z_level = ANTD_CNONE; + antd_task_t *task = NULL; + int client_sock = -1; + struct sockaddr_in client_name; + socklen_t client_name_len = sizeof(client_name); + char *client_ip = NULL; + config_t *conf = config(); + if (pcnf->sock > 0) + { + client_sock = accept(pcnf->sock, (struct sockaddr *)&client_name, &client_name_len); + if (client_sock > 0) + { + // just dump the scheduler when we have a connection + antd_client_t *client = (antd_client_t *)malloc(sizeof(antd_client_t)); + antd_request_t *request = (antd_request_t *)malloc(sizeof(*request)); + request->client = client; + request->request = dict(); + client->zstream = NULL; + client->z_level = ANTD_CNONE; - dictionary_t xheader = dict(); - dput(request->request, "REQUEST_HEADER", xheader); - dput(request->request, "REQUEST_DATA", dict()); - dput(request->request, "SERVER_PORT", (void *)__s("%d", pcnf->port)); - dput(request->request, "SERVER_WWW_ROOT", (void *)strdup(pcnf->htdocs)); - /* - get the remote IP - */ - if (client_name.sin_family == AF_INET) - { - client_ip = inet_ntoa(client_name.sin_addr); - LOG("Connect to client IP: %s on port:%d (%d)", client_ip, pcnf->port, client_sock); - // ip address - dput(request->request, "REMOTE_ADDR", (void *)strdup(client_ip)); - //LOG("socket: %d\n", client_sock); - } + dictionary_t xheader = dict(); + dput(request->request, "REQUEST_HEADER", xheader); + dput(request->request, "REQUEST_DATA", dict()); + dput(request->request, "SERVER_PORT", (void *)__s("%d", pcnf->port)); + dput(request->request, "SERVER_WWW_ROOT", (void *)strdup(pcnf->htdocs)); + /* + get the remote IP + */ + if (client_name.sin_family == AF_INET) + { + client_ip = inet_ntoa(client_name.sin_addr); + LOG("Connect to client IP: %s on port:%d (%d)", client_ip, pcnf->port, client_sock); + // ip address + dput(request->request, "REMOTE_ADDR", (void *)strdup(client_ip)); + // LOG("socket: %d\n", client_sock); + } - // set timeout to socket - set_nonblock(client_sock); + // set timeout to socket + set_nonblock(client_sock); - client->sock = client_sock; - time(&client->last_io); - client->ssl = NULL; - client->state = ANTD_CLIENT_ACCEPT; - client->z_status = 0; + client->sock = client_sock; + time(&client->last_io); + client->ssl = NULL; + client->state = ANTD_CLIENT_ACCEPT; + client->z_status = 0; #ifdef USE_OPENSSL - if (pcnf->usessl == 1) - { - client->ssl = (void *)SSL_new(ctx); - if (!client->ssl) - { - finish_request(request); - return; - } - SSL_set_fd((SSL *)client->ssl, client->sock); - // this can be used in the protocol select callback to - // set the protocol selected by the server - if (!SSL_set_ex_data((SSL *)client->ssl, client->sock, client)) - { - ERROR("Cannot set ex data to ssl client:%d", client->sock); - } - /*if (SSL_accept((SSL*)client->ssl) <= 0) { - LOG("EROOR accept\n"); - ERR_print_errors_fp(stderr); - antd_close(client); - continue; - }*/ - } + if (pcnf->usessl == 1) + { + client->ssl = (void *)SSL_new(ctx); + if (!client->ssl) + { + finish_request(request); + return; + } + SSL_set_fd((SSL *)client->ssl, client->sock); + // this can be used in the protocol select callback to + // set the protocol selected by the server + if (!SSL_set_ex_data((SSL *)client->ssl, client->sock, client)) + { + ERROR("Cannot set ex data to ssl client:%d", client->sock); + } + /*if (SSL_accept((SSL*)client->ssl) <= 0) { + LOG("EROOR accept\n"); + ERR_print_errors_fp(stderr); + antd_close(client); + continue; + }*/ + } #endif - antd_scheduler_lock(scheduler); - conf->connection++; - antd_scheduler_unlock(scheduler); - // create callback for the server - task = antd_create_task(accept_request, (void *)request, finish_request, client->last_io); - antd_task_bind_event(task, client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); - antd_scheduler_add_task(scheduler, task); - } - } + antd_scheduler_lock(scheduler); + conf->connection++; + antd_scheduler_unlock(scheduler); + // create callback for the server + task = antd_create_task(accept_request, (void *)request, finish_request, client->last_io); + antd_task_bind_event(task, client->sock, 0, TASK_EVT_ON_WRITABLE | TASK_EVT_ON_READABLE); + antd_scheduler_add_task(scheduler, task); + } + } } void antd_scheduler_ext_statistic(int fd, void *user_data) { - antd_request_t *request = (antd_request_t *)user_data; - chain_t it, it1; - dictionary_t tmp; - int ret; - char buff[BUFFLEN]; - if (request == NULL) - { - SEND_STAT(fd, buff, ret, "Data is null\n"); - return; - } - // send client general infomation - SEND_STAT(fd, buff, ret, "Client id: %d\n", request->client->sock); - SEND_STAT(fd, buff, ret, "Last IO: %lu\n", (unsigned long)request->client->last_io); - SEND_STAT(fd, buff, ret, "Current state: %d\n", request->client->state); - SEND_STAT(fd, buff, ret, "z_level: %d\n", request->client->z_level); - if (request->client->ssl) - { - SEND_STAT(fd, buff, ret, "SSL is enabled\n"); - } - // send client request detail - if (request->request) - { - for_each_assoc(it, request->request) - { - if (strcmp(it->key, "REQUEST_HEADER") == 0 || - strcmp(it->key, "REQUEST_DATA") == 0 || - strcmp(it->key, "COOKIE") == 0) - { - tmp = (dictionary_t)it->value; - if (tmp) - { - for_each_assoc(it1, tmp) - { - SEND_STAT(fd, buff, ret, "%s: %s\n", it1->key, (char *)it1->value); - } - } - } - else - { - SEND_STAT(fd, buff, ret, "%s: %s\n", it->key, (char *)it->value); - } - } - } - UNUSED(ret); + antd_request_t *request = (antd_request_t *)user_data; + chain_t it, it1; + dictionary_t tmp; + int ret; + char buff[BUFFLEN]; + if (request == NULL) + { + SEND_STAT(fd, buff, ret, "Data is null\n"); + return; + } + // send client general infomation + SEND_STAT(fd, buff, ret, "Client id: %d\n", request->client->sock); + SEND_STAT(fd, buff, ret, "Last IO: %lu\n", (unsigned long)request->client->last_io); + SEND_STAT(fd, buff, ret, "Current state: %d\n", request->client->state); + SEND_STAT(fd, buff, ret, "z_level: %d\n", request->client->z_level); + if (request->client->ssl) + { + SEND_STAT(fd, buff, ret, "SSL is enabled\n"); + } + // send client request detail + if (request->request) + { + for_each_assoc(it, request->request) + { + if (strcmp(it->key, "REQUEST_HEADER") == 0 || + strcmp(it->key, "REQUEST_DATA") == 0 || + strcmp(it->key, "COOKIE") == 0) + { + tmp = (dictionary_t)it->value; + if (tmp) + { + for_each_assoc(it1, tmp) + { + SEND_STAT(fd, buff, ret, "%s: %s\n", it1->key, (char *)it1->value); + } + } + } + else + { + SEND_STAT(fd, buff, ret, "%s: %s\n", it->key, (char *)it->value); + } + } + } + UNUSED(ret); } void antd_scheduler_destroy_data(void *data) { - antd_request_t *rq = (antd_request_t *)data; - antd_client_t *proxy = (antd_client_t *)dvalue(rq->request, "PROXY_HANDLE"); - if (proxy) - { - close(proxy->sock); - } - finish_request(data); + antd_request_t *rq = (antd_request_t *)data; + antd_client_t *proxy = (antd_client_t *)dvalue(rq->request, "PROXY_HANDLE"); + if (proxy) + { + close(proxy->sock); + } + finish_request(data); } int antd_scheduler_validate_data(antd_task_t *task) { - config_t *conf = config(); - return !(difftime(time(NULL), task->access_time) > conf->scheduler_timeout); + config_t *conf = config(); + return !(difftime(time(NULL), task->access_time) > conf->scheduler_timeout); } int antd_task_data_id(void *data) { - antd_request_t *rq = (antd_request_t *)data; - if (!rq) - return 0; - return antd_scheduler_next_id(scheduler, rq->client->sock); - /*UNUSED(data); - return antd_scheduler_next_id(scheduler,0);*/ + antd_request_t *rq = (antd_request_t *)data; + if (!rq) + return 0; + return antd_scheduler_next_id(scheduler, rq->client->sock); + /*UNUSED(data); + return antd_scheduler_next_id(scheduler,0);*/ } int main(int argc, char *argv[]) { - pthread_t sched_th; - // startup port - chain_t it; - struct timeval timeout; - port_config_t *pcnf; - fd_set master_set, working_set; - int status, maxfd = 0; - int nlisten = 0; - // load the config first - if (argc == 1) - load_config(CONFIG_FILE); - else - load_config(argv[1]); - // ignore the broken PIPE error when writing - //or reading to/from a closed socked connection - signal(SIGPIPE, SIG_IGN); - signal(SIGABRT, SIG_IGN); - signal(SIGINT, stop_serve); + pthread_t sched_th; + // startup port + chain_t it; + struct timeval timeout; + port_config_t *pcnf; + fd_set master_set, working_set; + int status, maxfd = 0; + int nlisten = 0; + // load the config first + if (argc == 1) + load_config(CONFIG_FILE); + else + load_config(argv[1]); + // ignore the broken PIPE error when writing + // or reading to/from a closed socked connection + signal(SIGPIPE, SIG_IGN); + signal(SIGABRT, SIG_IGN); + signal(SIGINT, stop_serve); - config_t *conf = config(); - // start syslog - if (conf->debug_enable == 1) - { - setlogmask(LOG_UPTO(LOG_NOTICE)); - } - else - { - setlogmask(LOG_UPTO(LOG_ERR)); - } - openlog(SERVER_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON); + config_t *conf = config(); + // start syslog + if (conf->debug_enable == 1) + { + setlogmask(LOG_UPTO(LOG_NOTICE)); + } + else + { + setlogmask(LOG_UPTO(LOG_ERR)); + } + openlog(SERVER_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON); #ifdef USE_OPENSSL - if (conf->enable_ssl == 1) - { - init_openssl(); - ctx = create_context(); + if (conf->enable_ssl == 1) + { + init_openssl(); + ctx = create_context(); - configure_context(ctx); - } + configure_context(ctx); + } #endif - // enable scheduler - // default to 4 workers - scheduler = antd_scheduler_init(conf->n_workers, conf->stat_fifo_path); - if (scheduler == NULL) - { - ERROR("Unable to initialise scheduler. Exit"); - stop_serve(0); - exit(1); - } - FD_ZERO(&master_set); - for_each_assoc(it, conf->ports) - { - pcnf = (port_config_t *)it->value; - if (pcnf) - { - pcnf->sock = startup(&pcnf->port); - if (pcnf->sock > 0) - { - set_nonblock(pcnf->sock); - FD_SET(pcnf->sock, &master_set); - LOG("Listening on port %d", pcnf->port); - maxfd = pcnf->sock > maxfd ? pcnf->sock : maxfd; - nlisten++; - } - else - { - ERROR("Port %d is disabled", pcnf->port); - } - } - } - if (nlisten == 0) - { - ERROR("No port is listenned, quit!!"); - stop_serve(0); - exit(1); - } - // Start scheduler - if (pthread_create(&sched_th, NULL, (void *(*)(void *))antd_scheduler_wait, (void *)scheduler) != 0) - { - ERROR("pthread_create: cannot start scheduler thread"); - stop_serve(0); - exit(1); - } - else - { - // reclaim data when exit - pthread_detach(sched_th); - } + // enable scheduler + // default to 4 workers + scheduler = antd_scheduler_init(conf->n_workers, conf->stat_fifo_path); + if (scheduler == NULL) + { + ERROR("Unable to initialise scheduler. Exit"); + stop_serve(0); + exit(1); + } + FD_ZERO(&master_set); + for_each_assoc(it, conf->ports) + { + pcnf = (port_config_t *)it->value; + if (pcnf) + { + pcnf->sock = startup(&pcnf->port); + if (pcnf->sock > 0) + { + set_nonblock(pcnf->sock); + FD_SET(pcnf->sock, &master_set); + LOG("Listening on port %d", pcnf->port); + maxfd = pcnf->sock > maxfd ? pcnf->sock : maxfd; + nlisten++; + } + else + { + ERROR("Port %d is disabled", pcnf->port); + } + } + } + if (nlisten == 0) + { + ERROR("No port is listenned, quit!!"); + stop_serve(0); + exit(1); + } + // Start scheduler + if (pthread_create(&sched_th, NULL, (void *(*)(void *))antd_scheduler_wait, (void *)scheduler) != 0) + { + ERROR("pthread_create: cannot start scheduler thread"); + stop_serve(0); + exit(1); + } + else + { + // reclaim data when exit + pthread_detach(sched_th); + } - while (antd_scheduler_ok(scheduler)) - { - if (conf->connection > conf->maxcon) - { - //ERROR("Reach max connection %d", conf->connection); - timeout.tv_sec = 0; - timeout.tv_usec = 10000; // 5 ms - select(0, NULL, NULL, NULL, &timeout); - continue; - } - FD_ZERO(&working_set); - memcpy(&working_set, &master_set, sizeof(master_set)); - // blocking select - status = select(maxfd + 1, &working_set, NULL, NULL, NULL); - if (status < 0) - { - ERROR("select() error: %s", strerror(errno)); - break; - } - if (status == 0) - { - continue; - } - for_each_assoc(it, conf->ports) - { - pcnf = (port_config_t *)it->value; - if (pcnf && pcnf->sock > 0 && FD_ISSET(pcnf->sock, &working_set)) - { - antd_monitor(pcnf); - } - } - } - stop_serve(0); - return (0); + while (antd_scheduler_ok(scheduler)) + { + if (conf->connection > conf->maxcon) + { + // ERROR("Reach max connection %d", conf->connection); + timeout.tv_sec = 0; + timeout.tv_usec = 10000; // 5 ms + select(0, NULL, NULL, NULL, &timeout); + continue; + } + FD_ZERO(&working_set); + memcpy(&working_set, &master_set, sizeof(master_set)); + // blocking select + status = select(maxfd + 1, &working_set, NULL, NULL, NULL); + if (status < 0) + { + ERROR("select() error: %s", strerror(errno)); + break; + } + if (status == 0) + { + continue; + } + for_each_assoc(it, conf->ports) + { + pcnf = (port_config_t *)it->value; + if (pcnf && pcnf->sock > 0 && FD_ISSET(pcnf->sock, &working_set)) + { + antd_monitor(pcnf); + } + } + } + stop_serve(0); + return (0); } diff --git a/lib/handle.c b/lib/handle.c index 539f250..1902c8c 100644 --- a/lib/handle.c +++ b/lib/handle.c @@ -106,28 +106,6 @@ int compressable(char *ctype) return 0; } -void htdocs(antd_request_t *rq, char *dest) -{ - //dictionary_t xheader = (dictionary_t)dvalue(rq->request, "REQUEST_HEADER"); - char *www = (char *)dvalue(rq->request, "SERVER_WWW_ROOT"); - if (www) - { - strcpy(dest, www); - } -} -void dbdir(char **dest) -{ - UNUSED(dest); -} -void tmpdir(char **dest) -{ - UNUSED(dest); -} -void plugindir(char **dest) -{ - UNUSED(dest); -} - const char *get_status_str(int stat) { switch (stat) @@ -1033,4 +1011,4 @@ void destroy_request(void *data) } antd_close(rq->client); free(rq); -} \ No newline at end of file +} diff --git a/lib/handle.h b/lib/handle.h index f648770..9094b75 100644 --- a/lib/handle.h +++ b/lib/handle.h @@ -30,6 +30,8 @@ #define ANTD_PLUGIN_READY 0x0 #define ANTD_PLUGIN_PANNIC 0x1 +#define ANTD_PLUGIN_INIT 0x2 +#define MAX_PATH_LEN 256 typedef enum { @@ -108,26 +110,22 @@ typedef struct typedef struct { - char name[128]; - char* dbpath; - char* tmpdir; - char* pdir; + char name[MAX_PATH_LEN]; + char dbpath[MAX_PATH_LEN]; + char tmpdir[MAX_PATH_LEN]; + char pdir[MAX_PATH_LEN]; dictionary_t config; int raw_body; int status; } plugin_header_t; -int __attribute__((weak)) require_plugin(const char *); -void __attribute__((weak)) htdocs(antd_request_t *rq, char *dest); -void __attribute__((weak)) dbdir(char **dest); -void __attribute__((weak)) tmpdir(char **dest); -void __attribute__((weak)) plugindir(char **dest); -int __attribute__((weak)) compressable(char *ctype); void set_nonblock(int socket); //void set_block(int socket); +int __attribute__((weak)) compressable(char *ctype); + void antd_send_header(void *, antd_response_header_t *); const char *get_status_str(int stat); int __t(void *, const char *, ...); diff --git a/lib/plugin.h b/lib/plugin.h index 0805cc2..1eb0519 100644 --- a/lib/plugin.h +++ b/lib/plugin.h @@ -40,13 +40,8 @@ STATIC PART, should be included in any plugin static plugin_header_t __plugin__; // private function -void __init_plugin__(const char* pl, dictionary_t* conf){ - strcpy(__plugin__.name,pl); - dbdir(&__plugin__.dbpath); - plugindir(&__plugin__.pdir); - tmpdir(&__plugin__.tmpdir); - __plugin__.config = conf; - __plugin__.raw_body = 0; +void __init_plugin__(plugin_header_t* pl, dictionary_t* conf){ + (void) memcpy(&__plugin__, pl, sizeof(plugin_header_t)); __plugin__.status = ANTD_PLUGIN_READY; init(); }; diff --git a/plugin_manager.c b/plugin_manager.c index 2b9bfee..ed17809 100644 --- a/plugin_manager.c +++ b/plugin_manager.c @@ -1,17 +1,20 @@ #include #include +#include +#include +#include +#include #include "plugin_manager.h" #include "lib/utils.h" #include "lib/handle.h" #include "http_server.h" - -static void unload_plugin_by_name(const char*); -static void * plugin_from_file(char* name, dictionary_t conf); +static void unload_plugin_by_name(const char *); +static void *plugin_from_file(char *name, char *path, dictionary_t conf); /** * Plugin table to store the loaded plugin */ -static struct plugin_entry *plugin_table[HASHSIZE]; +static struct plugin_entry *plugin_table[HASHSIZE]; /** * Locate a plugin in the plugin table @@ -23,14 +26,8 @@ struct plugin_entry *plugin_lookup(char *s) struct plugin_entry *np; for (np = plugin_table[hash(s, HASHSIZE)]; np != NULL; np = np->next) if (strcmp(s, np->pname) == 0) - return np; /* found */ - return NULL; /* not found */ -} - -int require_plugin(const char* name) -{ - struct plugin_entry* ptr = plugin_load((char*)name, NULL); - return ptr != NULL; + return np; /* found */ + return NULL; /* not found */ } /** @@ -40,160 +37,214 @@ int require_plugin(const char* name) * @param config: plugin configuration * @return pointer to the loaded plugin */ -struct plugin_entry *plugin_load(char *name, dictionary_t config) +struct plugin_entry *plugin_load(char *name, dictionary_t pconf) { - char* pname = NULL; + char *pname = NULL; + char path[BUFFLEN]; struct plugin_entry *np; unsigned hashval; - plugin_header_t *(*metafn)(); + plugin_header_t *(*metafn)(); plugin_header_t *meta = NULL; - char* error; - if(config) - { - pname = dvalue(config, "name"); - } - if(!pname) - { - pname = name; - } - if ((np = plugin_lookup(name)) == NULL) { /* not found */ - LOG("Loading plugin: %s -> %s", name, pname); - np = (struct plugin_entry *) malloc(sizeof(*np)); + config_t *sconf = config(); + int fromfd, tofd; + char *error; + struct stat st; + int is_tmp = 0; + if (pconf) + { + pname = dvalue(pconf, "name"); + } + if ((np = plugin_lookup(name)) == NULL) + { /* not found */ + LOG("Loading plugin: %s...", name); + np = (struct plugin_entry *)malloc(sizeof(*np)); if (np == NULL || name == NULL) { - if(np) free(np); - return NULL; - } - np->pname = strdup(name); - if ((np->handle = plugin_from_file(pname,config)) == NULL) - { - if(np->pname) free(np->pname); - if(np) free(np); - return NULL; - } - hashval = hash(name,HASHSIZE); + if (np) + free(np); + return NULL; + } + + (void)snprintf(path, sizeof(path), "%s/%s%s", sconf->plugins_dir, name, sconf->plugins_ext); + if (pname && strcmp(name, pname) != 0) + { + // copy plugin file to tmpdir + (void)snprintf(path, sizeof(path), "%s/%s%s", sconf->plugins_dir, pname, sconf->plugins_ext); + LOG("Original plugin file: %s", path); + if ((fromfd = open(path, O_RDONLY)) < 0) + { + ERROR("Unable to open file for reading %s: %s", path, strerror(errno)); + return NULL; + } + if (stat(path, &st) != 0) + { + close(fromfd); + ERROR("Unable to get file stat %s: %s", path, strerror(errno)); + return NULL; + } + (void)snprintf(path, sizeof(path), "%s/%s%s", sconf->tmpdir, name, sconf->plugins_ext); + LOG("TMP plugin file: %s", path); + if ((tofd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) + { + close(fromfd); + ERROR("Unable open file for reading %s: %s", path, strerror(errno)); + return NULL; + } + if (sendfile(tofd, fromfd, NULL, st.st_size) != st.st_size) + { + close(fromfd); + close(tofd); + ERROR("Unable to copy file: %s", strerror(errno)); + return NULL; + } + is_tmp = 1; + } + + np->pname = strdup(name); + np->handle = plugin_from_file(name, path, pconf); + if (is_tmp) + { + (void)remove(path); + } + if (np->handle == NULL) + { + if (np->pname) + free(np->pname); + if (np) + free(np); + return NULL; + } + hashval = hash(name, HASHSIZE); np->next = plugin_table[hashval]; plugin_table[hashval] = np; - } else /* already there */ + } + else /* already there */ { - LOG("The plugin %s id already loaded", name); + LOG("The plugin %s id already loaded", name); } - // check if plugin is ready - metafn = (plugin_header_t * (*)()) dlsym(np->handle, "meta"); + // check if plugin is ready + metafn = (plugin_header_t * (*)()) dlsym(np->handle, "meta"); if ((error = dlerror()) != NULL) { - ERROR("Unable to fetch plugin meta-data: [%s] %s", name, error); + ERROR("Unable to fetch plugin meta-data: [%s] %s", name, error); unload_plugin_by_name(name); - free(np); - return NULL; + free(np); + return NULL; } - meta = metafn(); - LOG("PLugin status: [%s] %d", name, meta->status); - if(!meta || meta->status != ANTD_PLUGIN_READY) - { - ERROR("Plugin is not ready or error: [%s].", name); + meta = metafn(); + LOG("PLugin status: [%s] %d", name, meta->status); + if (!meta || meta->status != ANTD_PLUGIN_READY) + { + ERROR("Plugin is not ready or error: [%s].", name); unload_plugin_by_name(name); - free(np); - return NULL; - } + free(np); + return NULL; + } return np; } /** * Find a plugin in a file, and load it in to the plugin table * @param name Name of the plugin - * @return + * @return */ -static void * plugin_from_file(char* name, dictionary_t conf) +static void *plugin_from_file(char *name, char *path, dictionary_t conf) { - void *lib_handle; - char* error; - char* path = __s("%s/%s%s",config()->plugins_dir,name,config()->plugins_ext); - void (*fn)(const char*, dictionary_t); - lib_handle = dlopen(path, RTLD_LAZY); - if (!lib_handle) - { - ERROR("Cannot load plugin '%s' : '%s'",name,dlerror()); - if(path) - free(path); - return NULL; - } - // set database path - fn = (void (*)(const char*, dictionary_t))dlsym(lib_handle, "__init_plugin__"); - if ((error = dlerror()) != NULL) - ERROR("Problem when finding plugin init function for %s : %s", name,error); - else - (*fn)(name, conf); - if(path) - free(path); - return lib_handle; + void *lib_handle; + char *error; + config_t *cnf = config(); + void (*fn)(plugin_header_t *, dictionary_t); + lib_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL /*| RTLD_NODELETE*/); + if (!lib_handle) + { + ERROR("Cannot load plugin '%s' : '%s'", name, dlerror()); + return NULL; + } + // set database path + fn = (void (*)(plugin_header_t *, dictionary_t))dlsym(lib_handle, "__init_plugin__"); + if ((error = dlerror()) != NULL) + ERROR("Problem when finding plugin init function for %s : %s", name, error); + else + { + plugin_header_t header; + strncpy(header.name, name, MAX_PATH_LEN - 1); + strncpy(header.dbpath, cnf->db_path, MAX_PATH_LEN - 1); + strncpy(header.tmpdir, cnf->tmpdir, MAX_PATH_LEN - 1); + strncpy(header.pdir, cnf->plugins_dir, MAX_PATH_LEN - 1); + header.config = conf; + header.raw_body = 0; + header.status = ANTD_PLUGIN_INIT; + (*fn)(&header, conf); + } + // trick libc that we close this lib, but it is not realy deleted + return lib_handle; } -void unload_plugin(struct plugin_entry* np) +void unload_plugin(struct plugin_entry *np) { - char* error; - void (*fn)() = NULL; - // find and execute the exit function - fn = (void(*)()) dlsym(np->handle, "__release__"); - if ((error = dlerror()) != NULL) - { - ERROR("Cant not release plugin %s : %s", np->pname,error); + char *error; + void (*fn)() = NULL; + // find and execute the exit function + fn = (void (*)())dlsym(np->handle, "__release__"); + if ((error = dlerror()) != NULL) + { + ERROR("Cant not release plugin %s : %s", np->pname, error); } - if(fn) - { - (*fn)(); - } - dlclose(np->handle); - //free((void *) np->handle); - if(np->pname) - free((void *) np->pname); + if (fn) + { + (*fn)(); + } + dlclose(np->handle); + // free((void *) np->handle); + if (np->pname) + free((void *)np->pname); } /* - Unload a plugin by its name + Unload a plugin by its name */ -void unload_plugin_by_name(const char* name) +void unload_plugin_by_name(const char *name) { - struct plugin_entry *np; - int hasval = hash(name, HASHSIZE); - np = plugin_table[hasval]; - if(strcmp(np->pname,name) == 0) - { - unload_plugin(np); - plugin_table[hasval] = np->next; - } - else - { - for (np = plugin_table[hasval] ; np != NULL; np = np->next) - { - if (np->next != NULL && strcmp(name, np->next->pname) == 0) - { - break; - } - } - if(np == NULL) return; // the plugin is is not loaded - unload_plugin(np->next); - np->next = np->next->next; - } + struct plugin_entry *np; + int hasval = hash(name, HASHSIZE); + np = plugin_table[hasval]; + if (strcmp(np->pname, name) == 0) + { + unload_plugin(np); + plugin_table[hasval] = np->next; + } + else + { + for (np = plugin_table[hasval]; np != NULL; np = np->next) + { + if (np->next != NULL && strcmp(name, np->next->pname) == 0) + { + break; + } + } + if (np == NULL) + return; // the plugin is is not loaded + unload_plugin(np->next); + np->next = np->next->next; + } } /** * Unload all the plugin loaded on the plugin table */ void unload_all_plugin() { - LOG("Unload all plugins"); - for(int i=0;inext; - unload_plugin(curr); - free(curr); - } + while ((curr = *np) != NULL) + { + (*np) = (*np)->next; + unload_plugin(curr); + free(curr); + } plugin_table[i] = NULL; - } - exit(0); + } + exit(0); } -