Mon, 06 Mar 2017 17:32:26 +0100
merge srvctrl into default branch
--- a/make/mingw.mk Mon Mar 06 17:30:52 2017 +0100 +++ b/make/mingw.mk Mon Mar 06 17:32:26 2017 +0100 @@ -33,6 +33,6 @@ CXX = g++ LD = g++ -SHLIB_CFLAGS = -fPIC +SHLIB_CFLAGS = SHLIB_LDFLAGS = -shared
--- a/make/solaris.mk Mon Mar 06 17:30:52 2017 +0100 +++ b/make/solaris.mk Mon Mar 06 17:32:26 2017 +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
--- a/src/server/Makefile Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/Makefile Mon Mar 06 17:32:26 2017 +0100 @@ -75,8 +75,8 @@ $(CC) -o $@ -c $(CFLAGS) $< -$(PLUGINS): $(MAIN_TARGET) +$(PLUGINS): $(MAIN_TARGET) FORCE cd plugins/$@/; $(MAKE) all - +FORCE:
--- a/src/server/config/keyfile.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/config/keyfile.c Mon Mar 06 17:32:26 2017 +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(
--- a/src/server/daemon/httplistener.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/daemon/httplistener.c Mon Mar 06 17:32:26 2017 +0100 @@ -50,6 +50,7 @@ #include "../util/atomic.h" #include "httplistener.h" +#include "netsite.h" #include "session.h" #include "configmanager.h" @@ -417,12 +418,12 @@ 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); free(conn); conn = NULL; - close(clientfd); + system_close(clientfd); } else { conn->ssl = ssl; conn->read = connection_ssl_read;
--- a/src/server/daemon/httpparser.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/daemon/httpparser.c Mon Mar 06 17:32:26 2017 +0100 @@ -131,11 +131,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(
--- a/src/server/daemon/httprequest.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/daemon/httprequest.c Mon Mar 06 17:32:26 2017 +0100 @@ -234,11 +234,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 +261,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); }
--- a/src/server/daemon/keyfile_auth.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/daemon/keyfile_auth.c Mon Mar 06 17:32:26 2017 +0100 @@ -29,7 +29,14 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> + #include <openssl/sha.h> +#if defined(__sun) && defined(__SunOS_5_10) +#include <sha2.h> +#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; } } +
--- a/src/server/daemon/keyfile_auth.h Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/daemon/keyfile_auth.h Mon Mar 06 17:32:26 2017 +0100 @@ -42,7 +42,9 @@ typedef struct keyfile_user KeyfileUser; enum KeyfileHashType { - KEYFILE_SSHA = 0 + KEYFILE_SSHA = 0, + KEYFILE_SSHA256, + KEYFILE_SSHA512 }; struct keyfile {
--- a/src/server/daemon/netsite.h Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/daemon/netsite.h Mon Mar 06 17:32:26 2017 +0100 @@ -142,6 +142,8 @@ /* --- End public functions --- */ +int system_close(int fd); + #ifdef __cplusplus } #endif
--- a/src/server/daemon/sessionhandler.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/daemon/sessionhandler.c Mon Mar 06 17:32:26 2017 +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) { @@ -320,7 +332,7 @@ int r = handle_request(request, NULL); if(r != 0) { // TODO: error message - close(request->connection->fd); + connection_destroy(request->connection); } /*
--- a/src/server/daemon/vfs.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/daemon/vfs.c Mon Mar 06 17:32:26 2017 +0100 @@ -32,10 +32,10 @@ #include <stdlib.h> #include <unistd.h> #include <sys/types.h> - #include <ucx/map.h> #include "../util/pool.h" +#include "netsite.h" #include "acl.h" #include "vfs.h" @@ -146,7 +146,7 @@ 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; } } @@ -155,7 +155,7 @@ VFSFile *file = pool ? pool_malloc(pool, sizeof(VFSFile)) : malloc(sizeof(VFSFile)); if(!file) { - close(fd); + system_close(fd); return NULL; } file->ctx = ctx; @@ -487,7 +487,7 @@ } void sys_file_close(SYS_FILE fd) { - close(fd->fd); + system_close(fd->fd); } int sys_dir_read(VFS_DIR dir, VFS_ENTRY *entry, int getstat) {
--- a/src/server/safs/cgi.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/safs/cgi.c Mon Mar 06 17:32:26 2017 +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 @@ } } } -
--- a/src/server/safs/common.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/safs/common.c Mon Mar 06 17:32:26 2017 +0100 @@ -38,7 +38,7 @@ static UcxMap *var_names; enum SAFVarNames { - COMMONSAF_INSERT_CLIENT = 0, + COMMONSAF_INSERT_CLIENT = 1, COMMONSAF_INSERT_VARS, COMMONSAF_INSERT_REQPB, COMMONSAF_INSERT_HEADERS, @@ -74,7 +74,7 @@ #define COMMONSAF_RET_ERROR -2 void common_saf_init() { - var_names = ucx_map_new(12); + var_names = ucx_map_new(32); ucx_map_cstr_put(var_names, "insert-client", (intptr_t)COMMONSAF_INSERT_CLIENT); ucx_map_cstr_put(var_names, "insert-vars", (intptr_t)COMMONSAF_INSERT_VARS); @@ -114,27 +114,79 @@ return REQ_NOACTION; } +static void var_set(char *value, pblock *pb, WSBool insert) { + sstr_t n; + sstr_t v; + v.ptr = NULL; + + n.ptr = value; + int i; + int len = strlen(value); + for(i=1;i<len;i++) { + if(value[i] == '=') { + n.length = i; + v = sstrsubs(sstrn(value, len), i + 1); + break; + } + } + if(!v.ptr || v.length == 0) { + log_ereport( + LOG_MISCONFIG, + "set-variable: string '%s' has not name=value format", + value); + return; + } + + if(!insert) { + // TODO + } + pblock_nvlinsert(n.ptr, n.length, v.ptr, v.length, pb); +} static int set_var(Session *sn, Request *rq, char *var, char *value) { intptr_t v = (intptr_t)ucx_map_cstr_get(var_names, var); switch(v) { default: break; - case COMMONSAF_INSERT_CLIENT: break; - case COMMONSAF_INSERT_VARS: break; - case COMMONSAF_INSERT_REQPB: break; - case COMMONSAF_INSERT_HEADERS: break; - case COMMONSAF_INSERT_SRVHDRS: break; - case COMMONSAF_SET_CLIENT: break; - case COMMONSAF_SET_VARS: break; - case COMMONSAF_SET_REQPB: break; - case COMMONSAF_SET_HEADERS: break; - case COMMONSAF_SET_SRVHDRS: break; - case COMMONSAF_REMOVE_CLIENT: break; - case COMMONSAF_REMOVE_VARS: break; - case COMMONSAF_REMOVE_HEADERS: break; - case COMMONSAF_REMOVE_SRVHDRS: break; + case COMMONSAF_INSERT_CLIENT: var_set(value, sn->client, TRUE); break; + case COMMONSAF_INSERT_VARS: var_set(value, rq->vars, TRUE); break; + case COMMONSAF_INSERT_REQPB: var_set(value, rq->reqpb, TRUE); break; + case COMMONSAF_INSERT_HEADERS: var_set(value, rq->headers, TRUE); break; + case COMMONSAF_INSERT_SRVHDRS: var_set(value, rq->srvhdrs, TRUE); break; + case COMMONSAF_SET_CLIENT: var_set(value, sn->client, FALSE); break; + case COMMONSAF_SET_VARS: var_set(value, rq->vars, FALSE); break; + case COMMONSAF_SET_REQPB: var_set(value, rq->reqpb, FALSE); break; + case COMMONSAF_SET_HEADERS: var_set(value, rq->headers, FALSE); break; + case COMMONSAF_SET_SRVHDRS: var_set(value, rq->srvhdrs, FALSE); break; + case COMMONSAF_REMOVE_CLIENT: pblock_remove(value, sn->client); break; + case COMMONSAF_REMOVE_VARS: pblock_remove(value, rq->vars); break; + 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<len;i++) { + if(!isdigit(value[i])) { + isnum = FALSE; + break; + } + } + + int64_t status; + int ret = util_strtoint(value, &status); + if(status < 100 || ret > 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; @@ -145,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;
--- a/src/server/util/io.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/util/io.c Mon Mar 06 17:32:26 2017 +0100 @@ -64,6 +64,7 @@ #include "../daemon/vfs.h" #include "io.h" #include "pool.h" +#include "../daemon/netsite.h" #include "ucx/utils.h" IOStream native_io_funcs = { @@ -167,7 +168,7 @@ #endif void net_sys_close(SysStream *st) { - close(st->fd); + system_close(st->fd); } #elif defined(XP_WIN32) @@ -334,7 +335,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) {
--- a/src/server/util/system.c Mon Mar 06 17:30:52 2017 +0100 +++ b/src/server/util/system.c Mon Mar 06 17:32:26 2017 +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) {