# HG changeset patch # User Olaf Wintermann # Date 1515866460 -3600 # Node ID aa8393527b1edf16d6373c696365c20e5432b1dc # Parent f33974f0dce0369c161914674f6c92b25d4e3fd8# Parent 6a145e13d933a1b1ef76e088411de65636b40107 merges aio into default branch diff -r 6a145e13d933 -r aa8393527b1e make/install.mk --- a/make/install.mk Sat Jan 13 18:48:19 2018 +0100 +++ b/make/install.mk Sat Jan 13 19:01:00 2018 +0100 @@ -46,7 +46,9 @@ sed s:%%WS_HOST%%:$(HOST):g ../templates/config/server.template > $(INSTALL_DIR)/config/server.conf @echo "copy binaries" cp ../build/bin/webservd$(APP_EXT) $(INSTALL_DIR)/bin/ + cp ../build/bin/wstool$(APP_EXT) $(INSTALL_DIR)/bin/ cp ../build/lib/libucx$(LIB_EXT) $(INSTALL_DIR)/lib/ + cp ../build/lib/libwscfg$(LIB_EXT) $(INSTALL_DIR)/lib/ @echo "copy includes" cp ../src/server/public/nsapi.h $(INSTALL_DIR)/include/nsapi.h cp ../src/server/public/auth.h $(INSTALL_DIR)/include/auth.h diff -r 6a145e13d933 -r aa8393527b1e make/mingw.mk --- a/make/mingw.mk Sat Jan 13 18:48:19 2018 +0100 +++ b/make/mingw.mk Sat Jan 13 19:01:00 2018 +0100 @@ -33,6 +33,6 @@ CXX = g++ LD = g++ -SHLIB_CFLAGS = -fPIC +SHLIB_CFLAGS = SHLIB_LDFLAGS = -shared diff -r 6a145e13d933 -r aa8393527b1e make/solaris.mk --- a/make/solaris.mk Sat Jan 13 18:48:19 2018 +0100 +++ b/make/solaris.mk Sat Jan 13 19:01:00 2018 +0100 @@ -29,7 +29,7 @@ # compiler and linker flags CFLAGS += -DSOLARIS -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -LDFLAGS += -lsocket -lnsl -lsendfile -lposix4 -lpthread -ldl -lm -lldap +LDFLAGS += -lsocket -lnsl -lsendfile -lposix4 -lpthread -ldl -lm -lmd -lldap #PLUGINS = java diff -r 6a145e13d933 -r aa8393527b1e src/Makefile --- a/src/Makefile Sat Jan 13 18:48:19 2018 +0100 +++ b/src/Makefile Sat Jan 13 19:01:00 2018 +0100 @@ -28,11 +28,17 @@ BUILD_ROOT = ../ -all: _ucx _server +all: ucx server tools -_ucx: +ucx: .FORCE cd ucx; $(MAKE) -_server: +server: ucx .FORCE cd server; $(MAKE) + +tools: server .FORCE + cd tools; $(MAKE) + +.FORCE: + \ No newline at end of file diff -r 6a145e13d933 -r aa8393527b1e src/server/Makefile --- a/src/server/Makefile Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/Makefile Sat Jan 13 19:01:00 2018 +0100 @@ -33,7 +33,9 @@ MAIN_TARGET = $(BUILD_ROOT)/build/bin/webservd -all: preparation $(MAIN_TARGET) $(PLUGINS) +LIB_WSCFG = $(BUILD_ROOT)/build/lib/libwscfg$(LIB_EXT) + +all: preparation $(MAIN_TARGET) $(LIB_WSCFG) $(PLUGINS) include util/objs.mk include safs/objs.mk @@ -65,13 +67,16 @@ $(MAIN_TARGET): $(MAINOBJS) $(CXX) -o $(MAIN_TARGET) $(MAINOBJS) -L$(BUILD_ROOT)/build/lib $(LDFLAGS) +$(LIB_WSCFG): $(CONFOBJS) + $(CC) $(SHLIB_LDFLAGS) -o $@ $(CONFOBJS) + ../../build/server/ucx/%.o: %.c $(CC) -o $@ -c $(CFLAGS) $< -$(PLUGINS): $(MAIN_TARGET) +$(PLUGINS): $(MAIN_TARGET) FORCE cd plugins/$@/; $(MAKE) all - +FORCE: diff -r 6a145e13d933 -r aa8393527b1e src/server/config/Makefile --- a/src/server/config/Makefile Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/config/Makefile Sat Jan 13 19:01:00 2018 +0100 @@ -27,8 +27,5 @@ # $(CONF_OBJPRE)%.o: config/%.c - $(CC) -o $@ -c $(CFLAGS) $< + $(CC) -o $@ -c $(CFLAGS) $(SHLIB_CFLAGS) $< -$(CONF_OBJPRE)%.o: config/%.cpp - $(CXX) -o $@ -c $(CFLAGS) $< - diff -r 6a145e13d933 -r aa8393527b1e src/server/config/keyfile.c --- a/src/server/config/keyfile.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/config/keyfile.c Sat Jan 13 19:01:00 2018 +0100 @@ -104,6 +104,10 @@ if(!sstrcmp(hash_type, sstr("SSHA"))) { entry->hashtype = KEYFILE_SSHA; + } else if(!sstrcmp(hash_type, sstr("SSHA256"))) { + entry->hashtype = KEYFILE_SSHA256; + } else if(!sstrcmp(hash_type, sstr("SSHA512"))) { + entry->hashtype = KEYFILE_SSHA512; } else { // unkown hash type log_ereport( diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/config.c diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/event.h diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/event_linux.c diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/event_solaris.c diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/httplistener.c --- a/src/server/daemon/httplistener.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/httplistener.c Sat Jan 13 19:01:00 2018 +0100 @@ -50,6 +50,7 @@ #include "../util/atomic.h" #include "httplistener.h" +#include "netsite.h" #include "session.h" #include "configmanager.h" diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/httpparser.c --- a/src/server/daemon/httpparser.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/httpparser.c Sat Jan 13 19:01:00 2018 +0100 @@ -35,7 +35,7 @@ HttpParser* http_parser_new(HTTPRequest *request) { - HttpParser *parser = malloc(sizeof(HttpParser)); + HttpParser *parser = calloc(1, sizeof(HttpParser)); parser->request = request; parser->state = 0; @@ -72,6 +72,18 @@ return -1; } +int http_parser_validate(HttpParser *parser) { + HTTPRequest *req = parser->request; + if( + !req->method.ptr || req->method.length == 0 + || !req->uri.ptr || req->uri.length == 0 + || !req->httpv.ptr || req->httpv.length == 0) + { + return 0; + } + return 1; +} + int get_start_line(HttpParser *parser) { netbuf *buf = parser->request->netbuf; while(buf->pos < buf->cursize) { @@ -131,11 +143,15 @@ return 0; } else { parser->offset = buf->pos; - if(parser->value.ptr != NULL) { - parser->value.length = (buf->inbuf + buf->pos - 1) + if(parser->name.length != 0) { + if(parser->value.ptr) { + parser->value.length = (buf->inbuf + buf->pos - 1) - (unsigned char*)parser->value.ptr; - if(buf->inbuf[buf->pos-2] == '\r') { - parser->value.length--; + if(buf->inbuf[buf->pos-2] == '\r') { + parser->value.length--; + } + } else { + parser->value.ptr = ""; } // add header header_add( diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/httpparser.h --- a/src/server/daemon/httpparser.h Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/httpparser.h Sat Jan 13 19:01:00 2018 +0100 @@ -74,6 +74,8 @@ */ int http_parser_process(HttpParser *parser); +int http_parser_validate(HttpParser *parser); + int get_start_line(HttpParser *parser); int http_parser_parse_header(HttpParser *parser); diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/httprequest.c --- a/src/server/daemon/httprequest.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/httprequest.c Sat Jan 13 19:01:00 2018 +0100 @@ -46,8 +46,7 @@ #include "error.h" void http_request_init(HTTPRequest *req) { - req->connection = NULL; - req->uri.ptr = NULL; + memset(req, 0, sizeof(HTTPRequest)); HeaderArray *hd = malloc(sizeof(HeaderArray)); hd->next = NULL; @@ -155,14 +154,13 @@ // Pass request line as "clf-request" // remove \r\n sstr_t clfreq = request->request_line; - while(clfreq.ptr[clfreq.length - 1] < 33) { + while(clfreq.length > 0 && clfreq.ptr[clfreq.length - 1] < 33) { clfreq.length--; } - request->request_line = clfreq; pblock_kvinsert( pb_key_clf_request, - request->request_line.ptr, - request->request_line.length, + clfreq.ptr, + clfreq.length, rq->rq.reqpb); // Pass method as "method" in reqpb, and also as method_num @@ -234,11 +232,22 @@ } // Get abs_path part of request URI, and canonicalize the path + sstr_t orig_path = absPath; absPath.ptr = util_canonicalize_uri( pool, absPath.ptr, absPath.length, (int*)&absPath.length); + if(!absPath.ptr) { + log_ereport( + LOG_WARN, + "invalid request path: {%.*s}", + (int)orig_path.length, + orig_path.ptr); + pool_destroy(pool); + // TODO: 400 bad request + return 1; + } // Decode the abs_path if(util_uri_unescape_strict(absPath.ptr)) { @@ -250,7 +259,12 @@ rq->rq.reqpb); } else { // TODO: log error - log_ereport(LOG_WARN, "uri unescape failed"); + log_ereport( + LOG_WARN, + "uri unescape failed: {%.*s}", + (int)absPath.length, + absPath.ptr); + // TODO: 400 bad request pblock_kvinsert(pb_key_uri, "/", 1, rq->rq.reqpb); } diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/keyfile_auth.c --- a/src/server/daemon/keyfile_auth.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/keyfile_auth.c Sat Jan 13 19:01:00 2018 +0100 @@ -29,7 +29,14 @@ #include #include #include + #include +#if defined(__sun) && defined(__SunOS_5_10) +#include +#define SHA256_Init SHA256Init +#define SHA256_Update SHA256Update +#define SHA256_Final SHA256Final +#endif #include "../util/atomic.h" #include "../util/util.h" @@ -113,10 +120,7 @@ int keyfile_user_verify_password(User *user, char *password) { KeyfileUser *usr = (KeyfileUser*)user; - switch(usr->hash_type) { - case KEYFILE_SSHA: return ssha_verify(usr, password); - } - return 0; + return ssha_verify(usr, password); } int keyfile_user_check_group(User *user, char *group) { @@ -137,26 +141,54 @@ int ssha_verify(KeyfileUser *user, char *password) { /* - * SSHA: SHA1(pw + salt) + 8 bytes salt + * SSHA: SHA(pw + salt) + salt * user->hash is already base64 decoded */ - // TODO: variable length salt + size_t hlen; + switch(user->hash_type) { + case KEYFILE_SSHA: hlen = 20; break; + case KEYFILE_SSHA256: hlen = 32; break; + case KEYFILE_SSHA512: hlen = 64; break; + } - char *salt = user->hash + user->hashlen - 8; // last 8 bytes are the salt - size_t pwlen = strlen(password); + char *salt = user->hash + hlen; + size_t saltlen = user->hashlen - hlen; + + size_t pwlen = strlen(password); - size_t saltpwlen = pwlen + 8; - char *saltpw = malloc(saltpwlen); - memcpy(saltpw, password, pwlen); - memcpy(saltpw + pwlen, salt, 8); + unsigned char pwhash[64]; + switch(user->hash_type) { + case KEYFILE_SSHA: { + SHA_CTX ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, password, pwlen); + SHA1_Update(&ctx, salt, saltlen); + SHA1_Final(pwhash, &ctx); + break; + } + case KEYFILE_SSHA256: { + SHA256_CTX ctx; + SHA256_Init(&ctx); + SHA256_Update(&ctx, password, pwlen); + SHA256_Update(&ctx, salt, saltlen); + SHA256_Final(pwhash, &ctx); + break; + } + case KEYFILE_SSHA512: { + SHA512_CTX ctx; + SHA512_Init(&ctx); + SHA512_Update(&ctx, password, pwlen); + SHA512_Update(&ctx, salt, saltlen); + SHA512_Final(pwhash, &ctx); + break; + } + } - unsigned char pwhash[20]; - SHA1((const unsigned char*)saltpw, saltpwlen, pwhash); - - if(!memcmp(user->hash, pwhash, 20)) { + if(!memcmp(user->hash, pwhash, hlen)) { return 1; } else { return 0; } } + diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/keyfile_auth.h --- a/src/server/daemon/keyfile_auth.h Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/keyfile_auth.h Sat Jan 13 19:01:00 2018 +0100 @@ -42,7 +42,9 @@ typedef struct keyfile_user KeyfileUser; enum KeyfileHashType { - KEYFILE_SSHA = 0 + KEYFILE_SSHA = 0, + KEYFILE_SSHA256, + KEYFILE_SSHA512 }; struct keyfile { diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/ldap_auth.h diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/log.c --- a/src/server/daemon/log.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/log.c Sat Jan 13 19:01:00 2018 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include "log.h" #include "../util/strbuf.h" @@ -43,12 +44,17 @@ #include "../util/atomic.h" #include +#include static int is_initialized = 0; static int log_file_fd; static int log_level = 0; +static uint32_t log_dup_count = 0; +static UcxList *log_dup_list = NULL; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + WSBool main_is_daemon(void); /* @@ -84,7 +90,8 @@ "failure", "catastrophe", "info", - "verbose" + "verbose", + "debug" }; static int can_log[] = { @@ -94,7 +101,8 @@ 1, // failure 1, // catastrophe 1, // info - 0 // verbose + 0, // verbose + 0 // debug }; int init_log_file(LogConfig *cfg) { @@ -114,10 +122,11 @@ can_log[LOG_INFORM] = 0; } else if(!strcmp(cfg->level, "WARNING")) { can_log[LOG_INFORM] = 0; - } else if(!strcmp(cfg->level, "INFO")) { - } else if(!strcmp(cfg->level, "VERBOSE")) { can_log[LOG_VERBOSE] = 1; + } else if(!strcmp(cfg->level, "DEBUG")) { + can_log[LOG_VERBOSE] = 1; + can_log[LOG_DEBUG] = 1; } if(cfg->log_stdout) { @@ -178,6 +187,21 @@ if(!main_is_daemon()) { writev(STDOUT_FILENO, io, 2); } + + if(log_dup_count > 0) { + char *msg = malloc(len + 1); + memcpy(msg, str, len); + msg[len] = '\n'; + + pthread_mutex_lock(&mutex); + UCX_FOREACH(elm, log_dup_list) { + LogDup *dup = elm->data; + dup->write(dup->cookie, msg, len + 1); + } + pthread_mutex_unlock(&mutex); + + free(msg); + } } sstr_t log_get_prefix(int level) { @@ -211,6 +235,27 @@ return d; } +void log_add_logdup(LogDup *dup) { + pthread_mutex_lock(&mutex); + log_dup_list = ucx_list_append(log_dup_list, dup); + ws_atomic_inc32(&log_dup_count); + pthread_mutex_unlock(&mutex); +} + +void log_remove_logdup(LogDup *ldup) { + pthread_mutex_lock(&mutex); + UcxList *elm = log_dup_list; + while(elm) { + if(elm->data == ldup) { + log_dup_list = ucx_list_remove(log_dup_list, elm); + ws_atomic_dec32(&log_dup_count); + break; + } + elm = elm->next; + } + pthread_mutex_unlock(&mutex); +} + /* * log api functions @@ -225,10 +270,10 @@ } int log_ereport_v(int degree, const char *format, va_list args) { - if(degree > 6) { + if(degree < 0 || degree > 7) { return 0; } - if(degree > 0 && !can_log[degree]) { + if(!can_log[degree]) { return 0; } diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/log.h --- a/src/server/daemon/log.h Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/log.h Sat Jan 13 19:01:00 2018 +0100 @@ -31,6 +31,7 @@ #include "../public/nsapi.h" #include +#include #include @@ -56,6 +57,11 @@ LogFile *log; } AccessLog; +typedef void (*log_writefunc)(void *cookie, char *msg, size_t length); +typedef struct { + log_writefunc write; + void *cookie; +} LogDup; // server logging int init_log_file(LogConfig *cfg); @@ -65,6 +71,8 @@ sstr_t log_get_prefix(int level); +void log_add_logdup(LogDup *dup); +void log_remove_logdup(LogDup *dup); // access logging LogFile* get_access_log_file(sstr_t file); diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/main.c --- a/src/server/daemon/main.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/main.c Sat Jan 13 19:01:00 2018 +0100 @@ -39,10 +39,13 @@ #include "../util/plist.h" #include "../util/date.h" +#include "../../ucx/string.h" + #include "webserver.h" #include "log.h" #include "httprequest.h" #include "httplistener.h" +#include "srvctrl.h" #include "configmanager.h" @@ -81,7 +84,7 @@ */ void sig_term(int sig) { webserver_shutdown(); - exit(EXIT_SUCCESS); + //exit(EXIT_SUCCESS); } void* log_pipe_thread(void *data) { @@ -164,17 +167,22 @@ int status; status = webserver_init(); if(status != 0) { - log_ereport(LOG_FAILURE, "Cannot initialize server."); + log_ereport(LOG_FAILURE, "cannot initialize server."); return EXIT_FAILURE; } status = webserver_run(); if(status != 0) { - log_ereport(LOG_FAILURE, "Cannot run server."); + log_ereport(LOG_FAILURE, "cannot run server."); return EXIT_FAILURE; } - + + if(srvctrl_wait()) { + return EXIT_FAILURE; + } + /* TODO: join threads (or not?) */ +/* while(1) { if(is_daemon) { fflush(stdout); @@ -185,6 +193,7 @@ break; } } +*/ return EXIT_SUCCESS; } diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/netsite.h --- a/src/server/daemon/netsite.h Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/netsite.h Sat Jan 13 19:01:00 2018 +0100 @@ -142,6 +142,8 @@ /* --- End public functions --- */ +int system_close(int fd); + #ifdef __cplusplus } #endif diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/objs.mk --- a/src/server/daemon/objs.mk Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/objs.mk Sat Jan 13 19:01:00 2018 +0100 @@ -44,6 +44,7 @@ DAEMONOBJ += sessionhandler.o DAEMONOBJ += vserver.o DAEMONOBJ += webserver.o +DAEMONOBJ += srvctrl.o DAEMONOBJ += ws-fn.o DAEMONOBJ += configmanager.o DAEMONOBJ += log.o diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/protocol.h diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/sessionhandler.c --- a/src/server/daemon/sessionhandler.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/sessionhandler.c Sat Jan 13 19:01:00 2018 +0100 @@ -55,7 +55,13 @@ } void connection_close(Connection *conn) { - close(conn->fd); + while(close(conn->fd)) { + if(errno != EINTR) { + log_ereport(LOG_VERBOSE, "connection close failed: %s", strerror(errno)); + break; + } + log_ereport(LOG_VERBOSE, "connection close: EINTR"); + } } int connection_ssl_read(Connection *conn, void *buf, int len) { @@ -82,7 +88,13 @@ log_ereport(LOG_VERBOSE, "SSL_shutdown failed: %d", conn->ssl_error); } } - close(conn->fd); + while(close(conn->fd)) { + if(errno != EINTR) { + log_ereport(LOG_VERBOSE, "connection close failed: %s", strerror(errno)); + break; + } + log_ereport(LOG_VERBOSE, "connection close: EINTR"); + } } void connection_destroy(Connection *conn) { @@ -170,6 +182,11 @@ } buf->cursize += r; } + if(!http_parser_validate(parser)) { + log_ereport(LOG_FAILURE, "http_parser_validate failed"); + // TODO: send error 400 bad request + return NULL; + } // process request r = handle_request(&request, NULL, NULL); // TODO: use correct thread pool @@ -280,7 +297,7 @@ case SSL_ERROR_WANT_ACCEPT: errstr = "SSL_ERROR_WANT_ACCEPT"; break; case SSL_ERROR_WANT_X509_LOOKUP: errstr = "SSL_ERROR_WANT_X509_LOOKUP"; break; case SSL_ERROR_SYSCALL: errstr = "SSL_ERROR_SYSCALL"; break; - case SSL_ERROR_SSL: errstr = "SL_ERROR_SSL"; break; + case SSL_ERROR_SSL: errstr = "SSL_ERROR_SSL"; break; log_ereport(LOG_VERBOSE, "SSL accept error[%d]: %s", error, errstr); event->finish = evt_request_error; @@ -358,8 +375,15 @@ event->finish = evt_request_error; io->error = 3; return 0; + } + + if(!http_parser_validate(parser)) { + log_ereport(LOG_FAILURE, "http_parser_validate failed"); + // TODO: send error 400 bad request + event->finish = evt_request_error; + return 0; } - + /* * process request * @@ -377,7 +401,7 @@ int r = handle_request(request, NULL, h); if(r != 0) { // TODO: error message - close(request->connection->fd); + connection_destroy(request->connection); } /* diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/srvctrl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/daemon/srvctrl.c Sat Jan 13 19:01:00 2018 +0100 @@ -0,0 +1,220 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "webserver.h" + +#include "../util/systhr.h" + +#include "../../ucx/utils.h" +#include "../../ucx/buffer.h" + +#include "srvctrl.h" + +#define SRVCTRL_THREAD_STACKSIZE 8192 + +static int srvctrl; +static sstr_t srvctrl_path; + +static WSBool srv_shutdown; + +int srvctrl_init(ServerConfiguration *cfg) { + // create srvctrl unix domain socket + // this socket is used for stop, reconfigure and other operations + srvctrl_path = ucx_sprintf("%s/private/srvctrl.sock", cfg->tmp.ptr); + struct sockaddr_un addr; + if(srvctrl_path.length > sizeof(addr.sun_path)-1) { + log_ereport( + LOG_CATASTROPHE, + "path '%s' too long for unix domain socket", + srvctrl_path.ptr); + return -1; + } + + // make sure there is no old srvctrl socket file + // otherweise bind would fail + if(unlink(srvctrl_path.ptr)) { + if(errno != ENOENT) { + log_ereport( + LOG_CATASTROPHE, + "cannot unlink old srvctrl socket '%s': %s", + srvctrl_path.ptr, + strerror(errno)); + return -1; + } + } + + ZERO(&addr, sizeof(addr)); + addr.sun_family = AF_UNIX; + memcpy(addr.sun_path, srvctrl_path.ptr, srvctrl_path.length); + + srvctrl = socket(AF_UNIX, SOCK_STREAM, 0); + if(srvctrl == -1) { + log_ereport( + LOG_CATASTROPHE, + "Cannot create server control socket: %s", + strerror(errno)); + return -1; + } + if(bind(srvctrl, (struct sockaddr*)&addr, sizeof(addr))) { + log_ereport( + LOG_CATASTROPHE, + "srvctrl socket bind failed: %s", + strerror(errno)); + return -1; + } + + return 0; +} + +int srvctrl_wait() { + listen(srvctrl, 8); + + for(;;) { + int fd = accept(srvctrl, NULL, 0); + if(fd < 0) { + if(srv_shutdown) break; + log_ereport( + LOG_FAILURE, + "srvctrl: accept failed: %s", + strerror(errno)); + break; + } + + SrvCtrlClient *client = srvctrl_create_client(fd); + SYS_THREAD t = systhread_start( + SYSTHREAD_DEFAULT_PRIORITY, + SRVCTRL_THREAD_STACKSIZE, + (thrstartfunc)srvctrl_thread, + client); + systhread_detach(t); + + } + + close(srvctrl); + unlink(srvctrl_path.ptr); + free(srvctrl_path.ptr); + + return 0; +} + +void srvctrl_shutdown() { + srv_shutdown = TRUE; + shutdown(srvctrl, SHUT_RDWR); +} + +SrvCtrlClient* srvctrl_create_client(int fd) { + SrvCtrlClient *client = malloc(sizeof(SrvCtrlClient)); + ZERO(client, sizeof(SrvCtrlClient)); + client->fd = fd; + return client; +} + +void* srvctrl_thread(SrvCtrlClient *client) { + LogDup log; + log.write = (log_writefunc)srvctrl_log; + log.cookie = client; + log_add_logdup(&log); + + char buf[64]; + UcxBuffer *line = ucx_buffer_new(NULL, 32, UCX_BUFFER_AUTOEXTEND); + + ssize_t r; + WSBool br = FALSE; + while((r = read(client->fd, buf, 64)) > 0) { + for(int i=0;ispace, line->pos); + if(srvctrl_handle_cmd(client, ln)) { + br = TRUE; + break; + } + } else { + ucx_buffer_putc(line, c); + } + } + if(br) { + break; + } + } + log_remove_logdup(&log); + + ucx_buffer_free(line); + close(client->fd); + free(client); + return NULL; +} + +int srvctrl_handle_cmd(SrvCtrlClient *client, sstr_t cmd) { + if(!sstrcmp(cmd, S("reconfig"))) { + log_ereport(LOG_INFORM, "reconfigure server"); + if(webserver_reconfig()) { + log_ereport(LOG_FAILURE, "cannot reload config"); + } else { + log_ereport(LOG_INFORM, "reconfig: success"); + } + } else if(!sstrcmp(cmd, S("shutdown"))) { + webserver_shutdown(); + } else if(!sstrcmp(cmd, S("stat"))) { + // TODO: implement + } else if(!sstrcmp(cmd, S("log"))) { + return 0; + } else { + log_ereport( + LOG_FAILURE, + "unknown srvctrl command: %.*s", + (int)cmd.length, + cmd.ptr); + } + return 1; +} + +void srvctrl_log(SrvCtrlClient *client, char *msg, size_t len) { + char msgheader[4]; + msgheader[0] = SRV_MSG_LOG; + uint16_t msglen = len; + memcpy(&msgheader[1], &msglen, 2); + write(client->fd, msgheader, 3); + + size_t pos = 0; + ssize_t w = 0; + while(pos < len) { + w = write(client->fd, msg + pos, len - pos); + if(w <= 0) { + break; + } + pos += w; + } +} diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/srvctrl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/daemon/srvctrl.h Sat Jan 13 19:01:00 2018 +0100 @@ -0,0 +1,67 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRVCTRL_H +#define SRVCTRL_H + +#include "../public/nsapi.h" + +#include "../../ucx/string.h" + +#include "config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SRV_MSG_RESPONSE 0 +#define SRV_MSG_LOG 1 + +typedef struct { + int fd; +} SrvCtrlClient; + +int srvctrl_init(ServerConfiguration *cfg); + +int srvctrl_wait(); + +void srvctrl_shutdown(); + +SrvCtrlClient* srvctrl_create_client(int fd); + +void* srvctrl_thread(SrvCtrlClient *client); +int srvctrl_handle_cmd(SrvCtrlClient *client, sstr_t cmd); +void srvctrl_log(SrvCtrlClient *client, char *msg, size_t len); + + +#ifdef __cplusplus +} +#endif + +#endif /* SRVCTRL_H */ + diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/vfs.c --- a/src/server/daemon/vfs.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/vfs.c Sat Jan 13 19:01:00 2018 +0100 @@ -33,10 +33,10 @@ #include #include #include - #include #include "../util/pool.h" +#include "netsite.h" #include "acl.h" #include "vfs.h" #include "threadpools.h" @@ -296,14 +296,14 @@ if(((oflags & O_CREAT) == O_CREAT) && sysacl.user_uid != -1) { if(fchown(fd, sysacl.user_uid, sysacl.user_gid)) { perror("vfs_open: fchown"); - close(fd); + system_close(fd); return NULL; } } VFSFile *file = VFS_MALLOC(pool, sizeof(VFSFile)); if(!file) { - close(fd); + system_close(fd); return NULL; } file->ctx = ctx; @@ -511,7 +511,7 @@ } void sys_file_close(SYS_FILE fd) { - close(fd->fd); + system_close(fd->fd); } int sys_file_aioread(aiocb_s *aiocb) { diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/webserver.c --- a/src/server/daemon/webserver.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/webserver.c Sat Jan 13 19:01:00 2018 +0100 @@ -48,6 +48,8 @@ #include "../util/io.h" #include "../util/util.h" +#include "../../ucx/utils.h" + #include "../safs/common.h" #include "func.h" @@ -57,6 +59,7 @@ #include "webserver.h" #include "log.h" #include "auth.h" +#include "srvctrl.h" extern struct FuncStruct webserver_funcs[]; @@ -91,20 +94,6 @@ // init caches auth_cache_init(); - // create tmp dir and pid file - char *mkdir_cmd = NULL; - asprintf(&mkdir_cmd, "mkdir -p %s", cfg->tmp.ptr); - system(mkdir_cmd); - free(mkdir_cmd); - - char *pid_file_path = NULL; - asprintf(&pid_file_path, "%s/pid", cfg->tmp.ptr); - FILE *pidfile = fopen(pid_file_path, "w"); // TODO: check error - pid_t pid = getpid(); - fprintf(pidfile, "%d", pid); - fclose(pidfile); - free(pid_file_path); - // init SAFs common_saf_init(); @@ -168,6 +157,50 @@ "server must be started as root to change uid"); } + // create tmp dir and pid file + char *mkdir_cmd = NULL; + asprintf(&mkdir_cmd, "mkdir -p %s", cfg->tmp.ptr); + system(mkdir_cmd); + free(mkdir_cmd); + + char *pid_file_path = NULL; + asprintf(&pid_file_path, "%s/pid", cfg->tmp.ptr); + FILE *pidfile = fopen(pid_file_path, "w"); // TODO: check error + pid_t pid = getpid(); + fprintf(pidfile, "%d", pid); + fclose(pidfile); + free(pid_file_path); + + // create unix domain socket for server control + sstr_t tmp_priv = ucx_sprintf("%s/private", cfg->tmp.ptr); + // TODO: remove existing private dir + if(mkdir(tmp_priv.ptr, S_IRWXU)) { + if(errno == EEXIST) { + if(chmod(tmp_priv.ptr, S_IRWXU)) { + log_ereport( + LOG_CATASTROPHE, + "cannot change permissions of tmp dir %s:", + tmp_priv.ptr, + strerror(errno)); + return 0; + } + } else { + log_ereport( + LOG_CATASTROPHE, + "cannot create tmp dir %s:", + tmp_priv.ptr, + strerror(errno)); + return -1; + } + } + + + // create srvctrl unix domain socket + // this socket is used for stop, reconfigure and other operations + if(srvctrl_init(cfg)) { + return -1; + } + //endpwent(); // TODO: close or not? //free(pwbuf); // TODO: ? @@ -190,6 +223,8 @@ void webserver_shutdown() { log_ereport(LOG_INFORM, "webserver shutdown"); + srvctrl_shutdown(); + // execute restart callbacks RestartCallback *re = atrestart; while(re) { @@ -198,6 +233,16 @@ } } +int webserver_reconfig() { + if(cfgmgr_load_config(NULL) != 0) { + return -1; + } + // start newly created listeners + start_all_listener(); + + return 0; +} + void webserver_atrestart(void (*fn)(void *), void *data) { RestartCallback *cb = malloc(sizeof(RestartCallback)); cb->func = fn; diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/webserver.h --- a/src/server/daemon/webserver.h Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/daemon/webserver.h Sat Jan 13 19:01:00 2018 +0100 @@ -45,6 +45,7 @@ int webserver_init(); int webserver_run(); void webserver_shutdown(); +int webserver_reconfig(); void webserver_atrestart(void (*fn)(void *), void *data); diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/websocket.c diff -r 6a145e13d933 -r aa8393527b1e src/server/daemon/ws-fn.c diff -r 6a145e13d933 -r aa8393527b1e src/server/plugins/java/Makefile --- a/src/server/plugins/java/Makefile Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/plugins/java/Makefile Sat Jan 13 19:01:00 2018 +0100 @@ -60,7 +60,7 @@ $(CC) -o $(NSAPI_JNI_LIB) $(JNI_OBJS) $(LDFLAGS) $(JAVA_WSRT): $(JAVASRC) - ant -Dbuild.compiler=javac1.7 compile jar + ant compile jar ../../../../build/server/plugins/java/%.o: %.c diff -r 6a145e13d933 -r aa8393527b1e src/server/public/auth.h diff -r 6a145e13d933 -r aa8393527b1e src/server/public/nsapi.h --- a/src/server/public/nsapi.h Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/public/nsapi.h Sat Jan 13 19:01:00 2018 +0100 @@ -176,6 +176,9 @@ */ #define LOG_VERBOSE 6 +// new +#define LOG_DEBUG 7 + /* * The time format to use in the error log */ diff -r 6a145e13d933 -r aa8393527b1e src/server/safs/cgi.c --- a/src/server/safs/cgi.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/safs/cgi.c Sat Jan 13 19:01:00 2018 +0100 @@ -39,7 +39,7 @@ #include "../util/util.h" #include "../util/pblock.h" #include "../../ucx/string.h" - +#include "../daemon/netsite.h" #include "../util/io.h" #include "cgiutils.h" @@ -104,7 +104,10 @@ r = netbuf_getbytes(sn->inbuf, buf, 4096); if(r <= 0) { // TODO: handle error - log_ereport(LOG_FAILURE, "send-cgi: Cannot read request body"); + log_ereport( + LOG_FAILURE, + "send-cgi: script: %s: cannot read request body", + path); kill(cgip.pid, SIGTERM); cgi_close(&cgip); return REQ_ABORTED; @@ -114,22 +117,24 @@ // TODO: handle error log_ereport( LOG_FAILURE, - "send-cgi: Cannot send request body to cgi process"); - kill(cgip.pid, SIGTERM); + "send-cgi: script: %s: cannot send request body to cgi process", + path); + kill(cgip.pid, SIGKILL); cgi_close(&cgip); return REQ_ABORTED; } n += r; } } - close(cgip.in[1]); + system_close(cgip.in[1]); cgip.in[1] = -1; // read from child CGIResponseParser *parser = cgi_parser_new(sn, rq); WSBool cgiheader = TRUE; ssize_t wr = 0; - int result = REQ_PROCEED; + int result = REQ_PROCEED; + size_t response_length = 0; while((r = read(cgip.out[0], buf, 4096)) > 0) { if(cgiheader) { size_t pos; @@ -148,6 +153,7 @@ } http_start_response(sn, rq); if(pos < r) { + response_length += r-pos; wr = net_write(sn->csd, &buf[pos], r-pos); if(wr <= 0) { result = REQ_ABORTED; @@ -156,6 +162,7 @@ } } } else { + response_length += r; wr = net_write(sn->csd, buf, r); if(wr <= 0) { result = REQ_ABORTED; @@ -164,6 +171,25 @@ } } + char *ctlen_header = pblock_findkeyval(pb_key_content_length, rq->srvhdrs); + if(ctlen_header) { + int64_t ctlenhdr; + if(util_strtoint(ctlen_header, &ctlenhdr)) { + if(ctlenhdr != response_length) { + log_ereport( + LOG_FAILURE, + "cgi-send: script: %s: content length mismatch", + path); + rq->rq_attr.keep_alive = 0; + result = REQ_ABORTED; + } + } + } + + if(result == REQ_ABORTED) { + log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", path); + kill(cgip.pid, SIGKILL); + } cgi_close(&cgip); // TODO: check return value cgi_parser_free(parser); @@ -212,13 +238,13 @@ // we need to close this unused pipe // otherwise stdin cannot reach EOF - close(p->in[1]); + system_close(p->in[1]); // execute program exit(execve(script.ptr, argv, envp)); } else { // parent - close(p->out[1]); + system_close(p->out[1]); p->out[1] = -1; } @@ -230,16 +256,16 @@ waitpid(p->pid, &status, 0); if(p->in[0] != -1) { - close(p->in[0]); + system_close(p->in[0]); } if(p->in[1] != -1) { - close(p->in[1]); + system_close(p->in[1]); } if(p->out[0] != -1) { - close(p->out[0]); + system_close(p->out[0]); } if(p->out[1] != -1) { - close(p->out[1]); + system_close(p->out[1]); } return 0; @@ -408,4 +434,3 @@ } } } - diff -r 6a145e13d933 -r aa8393527b1e src/server/safs/cgi.h diff -r 6a145e13d933 -r aa8393527b1e src/server/safs/common.c --- a/src/server/safs/common.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/safs/common.c Sat Jan 13 19:01:00 2018 +0100 @@ -162,7 +162,31 @@ case COMMONSAF_REMOVE_HEADERS: pblock_remove(value, rq->headers);break; case COMMONSAF_REMOVE_SRVHDRS: pblock_remove(value, rq->srvhdrs); break; case COMMONSAF_ABORT: return COMMONSAF_REQ_ABORTED; + case COMMONSAF_NOACTION: return COMMONSAF_RET_NOACTION; case COMMONSAF_ERROR: { + int len = strlen(value); + WSBool isnum = TRUE; + int i; + for(i=0;i 999 || !ret) { + log_ereport( + LOG_MISCONFIG, + "set-variable: error value must contain a 3-digit http status code"); + protocol_status(sn, rq, 500, NULL); + return COMMONSAF_RET_ERROR; + } + + char *msg = isnum ? NULL : sstrtrim(sstr(value + i)).ptr; + protocol_status(sn, rq, (int)status, msg); + return COMMONSAF_REQ_ABORTED; } case COMMONSAF_ESCAPE: break; @@ -173,7 +197,10 @@ rq->rq_attr.keep_alive = util_getboolean(var, 0); break; } - case COMMONSAF_NAME: break; + case COMMONSAF_NAME: { + pblock_kvinsert(pb_key_name, value, strlen(value), rq->vars); + break; + } case COMMONSAF_SENTHDRS: break; case COMMONSAF_STOP: return COMMONSAF_RET_STOP; case COMMONSAF_URL: break; diff -r 6a145e13d933 -r aa8393527b1e src/server/safs/common.h diff -r 6a145e13d933 -r aa8393527b1e src/server/safs/init.c diff -r 6a145e13d933 -r aa8393527b1e src/server/util/atomic.h diff -r 6a145e13d933 -r aa8393527b1e src/server/util/io.c --- a/src/server/util/io.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/util/io.c Sat Jan 13 19:01:00 2018 +0100 @@ -64,6 +64,7 @@ #include "../daemon/vfs.h" #include "io.h" #include "pool.h" +#include "../daemon/netsite.h" #include "../daemon/event.h" #include "ucx/utils.h" @@ -177,7 +178,7 @@ #endif void net_sys_close(SysStream *st) { - close(st->fd); + system_close(st->fd); } void net_sys_setmode(SysStream *st, int mode) { @@ -380,7 +381,7 @@ if(ret != 1) { st->error = SSL_get_error(st->ssl, ret); } - close(SSL_get_fd(st->ssl)); + system_close(SSL_get_fd(st->ssl)); } void net_ssl_finish(SSLStream *st) { diff -r 6a145e13d933 -r aa8393527b1e src/server/util/io.h diff -r 6a145e13d933 -r aa8393527b1e src/server/util/pblock.h diff -r 6a145e13d933 -r aa8393527b1e src/server/util/system.c --- a/src/server/util/system.c Sat Jan 13 18:48:19 2018 +0100 +++ b/src/server/util/system.c Sat Jan 13 19:01:00 2018 +0100 @@ -328,6 +328,17 @@ return dir; } +int system_close(int fd) { + while(close(fd)) { + if(errno != EINTR) { + return -1; + } else { + log_ereport(LOG_VERBOSE, "close interrupted by signal"); // TODO: use debug log level + } + } + return 0; +} + NSAPI_PUBLIC int getThreadMallocKey(void) { diff -r 6a145e13d933 -r aa8393527b1e src/server/util/systhr.c diff -r 6a145e13d933 -r aa8393527b1e src/server/util/uri.cpp diff -r 6a145e13d933 -r aa8393527b1e src/tools/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/Makefile Sat Jan 13 19:01:00 2018 +0100 @@ -0,0 +1,51 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2013 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +BUILD_ROOT = ../.. + +include $(BUILD_ROOT)/config.mk + +CFLAGS += -I.. +LDFLAGS += -L../../build/lib -lucx -lwscfg + +# list of source files +WSTOOL_SRC = wstool.c +WSTOOL_SRC += srvctrlsocket.c + +WSTOOL_OBJ = $(WSTOOL_SRC:%.c=$(BUILD_ROOT)/build/tools/%$(OBJ_EXT)) + +all: $(BUILD_ROOT)/build/tools $(BUILD_ROOT)/build/bin/wstool + +$(BUILD_ROOT)/build/bin/wstool: $(BUILD_ROOT)/build/tools $(WSTOOL_OBJ) + $(CC) -o $@ $(WSTOOL_OBJ) $(LDFLAGS) + +$(BUILD_ROOT)/build/tools/%$(OBJ_EXT): %.c + $(CC) $(CFLAGS) -c -o $@ $< + +$(BUILD_ROOT)/build/tools: + mkdir -p $(BUILD_ROOT)/build/tools diff -r 6a145e13d933 -r aa8393527b1e src/tools/srvctrlsocket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/srvctrlsocket.c Sat Jan 13 19:01:00 2018 +0100 @@ -0,0 +1,112 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "srvctrlsocket.h" + +#include +#include +#include +#include +#include +#include + +SrvConnection* srvctrl_connet(char *socketfile) { + if(!socketfile) { + fprintf(stderr, "srvctrl_connect: no socketfile\n"); + return NULL; + } + size_t len = strlen(socketfile); + if(len == 0) { + fprintf(stderr, "srvctrl_connect: invalid socket path\n"); + return NULL; + } + if(len > 100) { + fprintf(stderr, "srvctrl_connect: socket path too long\n"); + return NULL; + } + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if(fd == -1) { + perror("srvctrl_connect: cannot create socket"); + return NULL; + } + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + memcpy(addr.sun_path, socketfile, len); + + if(connect(fd, (struct sockaddr*)&addr, sizeof(addr))) { + perror("srvctrl_connect"); + close(fd); + return NULL; + } + + FILE *stream = fdopen(fd, "r+"); + if(!stream) { + close(fd); + return NULL; + } + + SrvConnection *conn = calloc(1, sizeof(SrvConnection)); + conn->socket = fd; + conn->stream = stream; + + return conn; +} + +void srvctrl_close(SrvConnection *conn) { + fclose(conn->stream); + free(conn); +} + +int srvctrl_readmsg(SrvConnection *conn, SrvMsg *msg) { + int type = 0; + uint16_t length; + + type = fgetc(conn->stream); + if(type == EOF) { + return 1; + } + + if(fread(&length, 1, 2, conn->stream) != 2) { + return -1; + } + + msg->type = type; + msg->length = length; + msg->message = malloc(length); + + size_t r = fread(msg->message, 1, length, conn->stream); + if(r != length) { + free(msg->message); + return -1; + } + + return 0; +} diff -r 6a145e13d933 -r aa8393527b1e src/tools/srvctrlsocket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/srvctrlsocket.h Sat Jan 13 19:01:00 2018 +0100 @@ -0,0 +1,75 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRVCTRLSOCKET_H +#define SRVCTRLSOCKET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SrvConnection { + int socket; + FILE *stream; +} SrvConnection; + +typedef struct SrvMsg { + /* + * message type + * 0: cmd response + * 1: log message + */ + int type; + + /* + * message data + */ + char *message; + + /* + * message length + */ + size_t length; +} SrvMsg; + +SrvConnection* srvctrl_connet(char *socketfile); + +void srvctrl_close(SrvConnection *conn); + +int srvctrl_readmsg(SrvConnection *conn, SrvMsg *msg); + +#ifdef __cplusplus +} +#endif + +#endif /* SRVCTRLSOCKET_H */ + diff -r 6a145e13d933 -r aa8393527b1e src/tools/wstool.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/wstool.c Sat Jan 13 19:01:00 2018 +0100 @@ -0,0 +1,123 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "wstool.h" + +#include +#include +#include + +#include "../server/config/serverconf.h" + +#include "srvctrlsocket.h" + +static void print_info(char *cmd) { + fprintf(stderr, "usage:\n"); + fprintf(stderr, "%s -t \n", cmd); + fprintf(stderr, "%s -s \n", cmd); + fprintf(stderr, "Commands: reconfig, shutdown, stat, log\n"); +} + +int main(int argc, char **argv) { + if(argc > 2) { + if(!strcmp(argv[1], "-t")) { + return tool_get_tmpdir(argv[2]); + } else if(!strcmp(argv[1], "-s")) { + if(argc != 4) { + print_info(argv[0]); + return -2; + } + return tool_srvctrl(argv[2], argv[3]); + } + } + + print_info(argv[0]); + return -2; +} + +int tool_get_tmpdir(char *configfile) { + ServerConfig *serverconf = load_server_config(configfile); + UcxList *list = ucx_map_sstr_get(serverconf->objects, sstrn("Runtime", 7)); + if(!list) { + fprintf(stderr, "Error: No Runtime element in %s\n", configfile); + return -1; + } + if(ucx_list_size(list) != 1) { + fprintf(stderr, "Error: Multiple Runtime elements in %s\n", configfile); + return -1; + } + ServerConfigObject *runtime = list->data; + sstr_t tmp = cfg_directivelist_get_str(runtime->directives, sstr("Temp")); + if(!tmp.ptr) { + fprintf(stderr, "Error: No Temp directive in Runtime Object\n"); + return -1; + } + + printf("%.*s\n", (int)tmp.length, tmp.ptr); + + return 0; +} + +int tool_srvctrl(char *socketfile, char *cmd) { + SrvConnection *srv = srvctrl_connet(socketfile); + if(!srv) { + return -1; + } + + fprintf(srv->stream, "%s\n", cmd); + fflush(srv->stream); + + SrvMsg msg; + while(!srvctrl_readmsg(srv, &msg)) { + if(msg.type == 0) { + fprintf(stdout, "%.*s", (int)msg.length, msg.message); + fflush(stdout); + } else if(msg.type == 1) { + fprintf(stderr, "%.*s", (int)msg.length, msg.message); + fflush(stderr); + } + } + + srvctrl_close(srv); + + return 0; +} + + + +int log_ereport(int degree, const char *format, ...) { + va_list args; + va_start(args, format); + int ret = log_ereport_v(degree, format, args); + va_end(args); + return ret; +} + +int log_ereport_v(int degree, const char *format, va_list args) { + return 0; +} diff -r 6a145e13d933 -r aa8393527b1e src/tools/wstool.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/wstool.h Sat Jan 13 19:01:00 2018 +0100 @@ -0,0 +1,50 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WSTOOL_H +#define WSTOOL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int tool_get_tmpdir(char *configfile); + +int tool_srvctrl(char *socketfile, char *cmd); + +int log_ereport(int degree, const char *format, ...); +int log_ereport_v(int degree, const char *format, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif /* WSTOOL_H */ + diff -r 6a145e13d933 -r aa8393527b1e templates/bin/reconfig.template --- a/templates/bin/reconfig.template Sat Jan 13 18:48:19 2018 +0100 +++ b/templates/bin/reconfig.template Sat Jan 13 19:01:00 2018 +0100 @@ -1,6 +1,57 @@ #!/bin/sh -PID=`cat /tmp/webserver-rw6pgl8b/pid` +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2017 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# -kill -USR1 $PID +WS_INSTALL_DIR=%%WS_INSTALL_DIR%% + +cd $WS_INSTALL_DIR + +WS_TMP_DIR=`bin/wstool -t config/server.conf` +if [ $? -ne 0 ]; then + exit 1 +fi +WS_PID=`cat $WS_TMP_DIR/pid 2> /dev/null` +if [ $? -ne 0 ]; then + echo "cannot get server pid" + exit 1 +fi +if [ -z $WS_PID ]; then + echo "cannot get server pid" + exit 1 +fi + +kill -0 $WS_PID 2> /dev/null +if [ $? -ne 0 ]; then + echo "server not running" + exit 1 +fi + +bin/wstool -s $WS_TMP_DIR/private/srvctrl.sock reconfig + diff -r 6a145e13d933 -r aa8393527b1e templates/bin/startserv.template --- a/templates/bin/startserv.template Sat Jan 13 18:48:19 2018 +0100 +++ b/templates/bin/startserv.template Sat Jan 13 19:01:00 2018 +0100 @@ -3,7 +3,7 @@ # # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. # -# Copyright 2011 Olaf Wintermann. All rights reserved. +# Copyright 2017 Olaf Wintermann. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: diff -r 6a145e13d933 -r aa8393527b1e templates/bin/stopserv.template --- a/templates/bin/stopserv.template Sat Jan 13 18:48:19 2018 +0100 +++ b/templates/bin/stopserv.template Sat Jan 13 19:01:00 2018 +0100 @@ -1,6 +1,56 @@ #!/bin/sh -PID=`cat /tmp/webserver-rw6pgl8b/pid` +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2017 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# -kill -TERM $PID +WS_INSTALL_DIR=%%WS_INSTALL_DIR%% + +cd $WS_INSTALL_DIR + +WS_TMP_DIR=`bin/wstool -t config/server.conf` +if [ $? -ne 0 ]; then + exit 1 +fi +WS_PID=`cat $WS_TMP_DIR/pid 2> /dev/null` +if [ $? -ne 0 ]; then + echo "cannot get server pid" + exit 1 +fi +if [ -z $WS_PID ]; then + echo "cannot get server pid" + exit 1 +fi + +kill -0 $WS_PID 2> /dev/null +if [ $? -ne 0 ]; then + echo "server not running" + exit 1 +fi + +bin/wstool -s $WS_TMP_DIR/private/srvctrl.sock shutdown