Index: src/Makefile.am =================================================================== --- src/Makefile.am (revision 2989) +++ src/Makefile.am (working copy) @@ -272,7 +272,7 @@ md5.h http_auth.h stream.h \ fdevent.h connections.h base.h stat_cache.h \ plugin.h mod_auth.h \ - etag.h joblist.h array.h crc32.h \ + etaginit.h joblist.h array.h crc32.h \ network_backends.h configfile.h \ mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \ configparser.h mod_ssi_exprparser.h \ Index: src/base.h =================================================================== --- src/base.h (revision 2989) +++ src/base.h (working copy) @@ -1,14 +1,22 @@ #ifndef _BASE_H_ #define _BASE_H_ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "settings.h" +typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t; + #include #include #include +#include +#include #include @@ -27,9 +35,34 @@ #include "fdevent.h" #include "sys-socket.h" #include "splaytree.h" -#include "etag.h" +#ifndef __INTEL_COMPILER +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __must_check __attribute__((warn_unused_result)) +#else +#define __must_check +#endif +#else +#define __must_check +#endif +/* + * min()/max() macros that also do + * strict type-checking.. See the + * "unnecessary" pointer comparison. + */ +#define min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H # define USE_OPENSSL # include @@ -50,6 +83,10 @@ # define O_LARGEFILE 0 #endif +#ifndef O_CLOEXEC +# error needs O_CLOEXEC +#endif + #ifndef SIZE_MAX # ifdef SIZE_T_MAX # define SIZE_MAX SIZE_T_MAX @@ -213,9 +250,16 @@ buffer *etag; struct stat st; - + uint64_t fs_type; + unsigned char fs_fsid[16]; time_t stat_ts; + enum { + STAT_CACHE_ENTRY_UNSET, + STAT_CACHE_ENTRY_ASYNC_STAT, + STAT_CACHE_ENTRY_STAT_FINISHED + } state; + #ifdef HAVE_LSTAT char is_symlink; #endif @@ -418,7 +462,7 @@ /* response */ int got_response; - + int bad_host; int in_joblist; connection_type mode; @@ -653,5 +697,8 @@ gid_t gid; } server; +extern int etag_is_equal(buffer *etag, const char *matches); +extern int etag_create(stat_cache_entry *sce, etag_flags_t flags); +extern int etag_mutate(buffer *mut, buffer *etag); #endif Index: src/configfile.c =================================================================== --- src/configfile.c (revision 2989) +++ src/configfile.c (working copy) @@ -2,7 +2,7 @@ #include "log.h" #include "stream.h" #include "plugin.h" - +#include "config.h" #include "configparser.h" #include "configfile.h" #include "proc_open.h" Index: src/connections.c =================================================================== --- src/connections.c (revision 2989) +++ src/connections.c (working copy) @@ -1097,7 +1097,8 @@ cnt_len = sizeof(cnt_addr); - if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) { + if (-1 == (cnt = accept4(srv_socket->fd, (struct sockaddr *) &cnt_addr, + &cnt_len, SOCK_NONBLOCK | SOCK_CLOEXEC))) { switch (errno) { case EAGAIN: #if EWOULDBLOCK != EAGAIN @@ -1143,10 +1144,12 @@ buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); con->srv_socket = srv_socket; +#if 0 if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); return NULL; } +#endif #ifdef USE_OPENSSL /* connect FD to SSL */ if (srv_socket->is_ssl) { Index: src/etag.c =================================================================== --- src/etag.c (revision 2989) +++ src/etag.c (working copy) @@ -1,51 +1,128 @@ -#include "buffer.h" -#include "etag.h" +#include +#include +#include +#include +#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #if defined HAVE_STDINT_H -# include +#include #elif defined HAVE_INTTYPES_H -# include +#include #endif -#include +#include "buffer.h" +#include "etaginit.h" +#include "misc.h" +#include "base.h" +/* ETag generation */ + +#define ROTL64(a,b) (((a)<<(b))|((a)>>(64-b))) + +static uint64_t U8TO64_LE(const unsigned char *p) { + return *(const uint64_t *)p; +} + int etag_is_equal(buffer *etag, const char *matches) { if (etag && !buffer_string_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1; return 0; } -int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) { - if (0 == flags) return 0; +static uint64_t siphash(unsigned char key[16], unsigned char *m, size_t len) { + uint64_t v0, v1, v2, v3; + uint64_t mi, k0, k1; + uint64_t last7; + size_t i, blocks; - buffer_reset(etag); + k0 = U8TO64_LE(key + 0); + k1 = U8TO64_LE(key + 8); + v0 = k0 ^ 0x736f6d6570736575ull; + v1 = k1 ^ 0x646f72616e646f6dull; + v2 = k0 ^ 0x6c7967656e657261ull; + v3 = k1 ^ 0x7465646279746573ull; + last7 = (uint64_t)(len & 0xff) << 56; + +#define sipcompress() \ + v0 += v1; v2 += v3; \ + v1 = ROTL64(v1,13); v3 = ROTL64(v3,16); \ + v1 ^= v0; v3 ^= v2; \ + v0 = ROTL64(v0,32); \ + v2 += v1; v0 += v3; \ + v1 = ROTL64(v1,17); v3 = ROTL64(v3,21); \ + v1 ^= v2; v3 ^= v0; \ + v2 = ROTL64(v2,32); + + for (i = 0, blocks = (len & ~7); i < blocks; i += 8) { + mi = U8TO64_LE(m + i); + v3 ^= mi; + sipcompress() + sipcompress() + v0 ^= mi; + } + + switch (len - blocks) { + case 7: last7 |= (uint64_t)m[i + 6] << 48; + case 6: last7 |= (uint64_t)m[i + 5] << 40; + case 5: last7 |= (uint64_t)m[i + 4] << 32; + case 4: last7 |= (uint64_t)m[i + 3] << 24; + case 3: last7 |= (uint64_t)m[i + 2] << 16; + case 2: last7 |= (uint64_t)m[i + 1] << 8; + case 1: last7 |= (uint64_t)m[i + 0] ; + case 0: + default:; + }; + v3 ^= last7; + sipcompress() + sipcompress() + v0 ^= last7; + v2 ^= 0xff; + sipcompress() + sipcompress() + sipcompress() + sipcompress() + return v0 ^ v1 ^ v2 ^ v3; +} + +static void stat_to_etag(buffer *etagb, char *etag_out) { + uint64_t etag_sip; + static unsigned char etag_key[16] = ETAGINIT; + + etag_sip = siphash(etag_key, (unsigned char*)etagb->ptr, etagb->used); + base32encode(&etag_sip, etag_out, sizeof(etag_sip), 0); +} + +int etag_create(stat_cache_entry *sce, etag_flags_t flags) { + uint64_t etag_tmp[4] = {0}; + if (flags & ETAG_USE_INODE) { - buffer_append_int(etag, st->st_ino); - buffer_append_string_len(etag, CONST_STR_LEN("-")); + etag_tmp[0] = sce->st.st_ino; } - if (flags & ETAG_USE_SIZE) { - buffer_append_int(etag, st->st_size); - buffer_append_string_len(etag, CONST_STR_LEN("-")); + etag_tmp[1] = sce->st.st_size; } - if (flags & ETAG_USE_MTIME) { - buffer_append_int(etag, st->st_mtime); + etag_tmp[2] = sce->st.st_mtim.tv_sec; + etag_tmp[3] = sce->st.st_mtim.tv_nsec; } + buffer_string_prepare_copy(sce->etag, sizeof(etag_tmp)); + memcpy(sce->etag->ptr, etag_tmp, sizeof(etag_tmp)); + sce->etag->used = sizeof(etag_tmp); return 0; } int etag_mutate(buffer *mut, buffer *etag) { - size_t i, len; - uint32_t h; + char etag_base32[16]; - len = buffer_string_length(etag); - for (h=0, i=0; i < len; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]); - + stat_to_etag(etag, etag_base32); buffer_reset(mut); buffer_copy_string_len(mut, CONST_STR_LEN("\"")); - buffer_append_int(mut, h); + buffer_append_string_len(mut, etag_base32, 12); buffer_append_string_len(mut, CONST_STR_LEN("\"")); return 0; Index: src/etag.h =================================================================== --- src/etag.h (revision 2989) +++ src/etag.h (working copy) @@ -1,17 +0,0 @@ -#ifndef ETAG_H -#define ETAG_H - -#include "buffer.h" - -#include -#include -#include - -typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t; - -int etag_is_equal(buffer *etag, const char *matches); -int etag_create(buffer *etag, struct stat *st, etag_flags_t flags); -int etag_mutate(buffer *mut, buffer *etag); - - -#endif Index: src/etaginit.h =================================================================== --- src/etaginit.h (revision 0) +++ src/etaginit.h (working copy) @@ -0,0 +1,7 @@ +#ifndef ETAGINIT_H +#define ETAGINIT_H + +#define ETAGINIT "rt51pggnm94e2f2n" + +#endif + Property changes on: src/etaginit.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +LF \ No newline at end of property Index: src/fdevent_linux_sysepoll.c =================================================================== --- src/fdevent_linux_sysepoll.c (revision 2989) +++ src/fdevent_linux_sysepoll.c (working copy) @@ -133,15 +133,13 @@ SET(event_get_fd); SET(event_get_revent); - if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) { + if (-1 == (ev->epoll_fd = epoll_create1(O_CLOEXEC))) { log_error_write(ev->srv, __FILE__, __LINE__, "SSS", - "epoll_create failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\""); + "epoll_create1 failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\""); return -1; } - fd_close_on_exec(ev->epoll_fd); - ev->epoll_events = malloc(ev->maxfds * sizeof(*ev->epoll_events)); return 0; Index: src/http-header-glue.c =================================================================== --- src/http-header-glue.c (revision 2989) +++ src/http-header-glue.c (working copy) @@ -2,7 +2,6 @@ #include "array.h" #include "buffer.h" #include "log.h" -#include "etag.h" #include "response.h" #include Index: src/log.c =================================================================== --- src/log.c (revision 2989) +++ src/log.c (working copy) @@ -71,9 +71,9 @@ /* dup the filehandle to STDIN */ if (to_log_fds[0] != STDIN_FILENO) { - if (STDIN_FILENO != dup2(to_log_fds[0], STDIN_FILENO)) { + if (STDIN_FILENO != dup3(to_log_fds[0], STDIN_FILENO, O_CLOEXEC)) { log_error_write(srv, __FILE__, __LINE__, "ss", - "dup2 failed: ", strerror(errno)); + "dup3 failed: ", strerror(errno)); exit(-1); } close(to_log_fds[0]); @@ -80,16 +80,6 @@ } close(to_log_fds[1]); -#ifndef FD_CLOEXEC - { - int i; - /* we don't need the client socket */ - for (i = 3; i < 256; i++) { - close(i); - } - } -#endif - /* close old stderr */ openDevNull(STDERR_FILENO); @@ -114,7 +104,7 @@ #else return -1; #endif - } else if (-1 == (fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { + } else if (-1 == (fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE | O_CLOEXEC, 0644))) { log_error_write(srv, __FILE__, __LINE__, "SSSS", "opening errorlog '", logfile, "' failed: ", strerror(errno)); @@ -122,8 +112,6 @@ return -1; } - fd_close_on_exec(fd); - return fd; } Index: src/misc.h =================================================================== --- src/misc.h (revision 0) +++ src/misc.h (working copy) @@ -0,0 +1,108 @@ +#ifndef _MISC_H_ +#define _MISC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ROTATE(v,c) (((v) << (c)) | ((v) >> (32 - (c)))) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \ + x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \ + x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \ + x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7); + +static void salsa20(void *__out, void *__in) +{ + int i; + uint32_t x[16]; + uint32_t *input = __in; + uint32_t *output32 = __out; + + for (i = 0;i < 16;++i) x[i] = input[i]; + for (i = 12;i > 0;i -= 2) { + QUARTERROUND( 0, 4, 8,12) + QUARTERROUND( 1, 5, 9,13) + QUARTERROUND( 2, 6,10,14) + QUARTERROUND( 3, 7,11,15) + QUARTERROUND( 0, 5,10,15) + QUARTERROUND( 1, 6,11,12) + QUARTERROUND( 2, 7, 8,13) + QUARTERROUND( 3, 4, 9,14) + } + for (i = 0;i < 16;++i) x[i] = PLUS(x[i],input[i]); + for (i = 0;i < 16;++i) output32[i] = x[i]; +} + +static __thread uint32_t salsa20_out[16]; +static __thread uint32_t salsa20_in[16]; +static __thread int salsa20_nrints; +static __thread int salsa20_init; + +static inline uint32_t get_random32(void) +{ + if (!salsa20_init) { + int fd; + + salsa20_init = 1; + salsa20_in[0] = time(NULL); + salsa20_in[1] = getpid(); + fd = open("/dev/urandom", O_RDONLY); + if (fd != -1) { + read(fd, salsa20_in, sizeof(salsa20_in)); + close(fd); + } + } + + if (salsa20_nrints == 0) { + if (!++salsa20_in[0]) if (!++salsa20_in[1]) if (!++salsa20_in[2]) if (!++salsa20_in[3]) + if (!++salsa20_in[4]) if (!++salsa20_in[5]) if (!++salsa20_in[6]) if (!++salsa20_in[7]) + if (!++salsa20_in[8]) if (!++salsa20_in[9]) if (!++salsa20_in[10]) if (!++salsa20_in[11]) + if (!++salsa20_in[12]) if (!++salsa20_in[13]) if (!++salsa20_in[14]) ++salsa20_in[15]; + salsa20(salsa20_out, salsa20_in); + salsa20_nrints = 16; + } + + return salsa20_out[--salsa20_nrints]; +} + +static const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567"; + +static inline void base32encode(void* __in, void* __out, unsigned long int len, int terminate) +{ + unsigned char ch1, ch2; + int bits; + unsigned char *in = __in; + unsigned char *out = __out; + + for (ch2 = 0, bits = 5; len; len--) { + ch1 = *in++; + if (bits > 3) { + ch2 |= ch1 >> (8 - bits); + *out++ = base32[ch2]; + bits -= 3; + ch2 = (ch1 << bits) & 31; + } else { + ch2 |= ch1 >> (8 - bits); + *out++ = base32[ch2]; + ch2 = (ch1 >> (3 - bits)) & 31; + *out++ = base32[ch2]; + bits += 2; + ch2 = (ch1 << bits) & 31; + } + } + if (terminate) *out = 0; +} + +#endif + Property changes on: src/misc.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +LF \ No newline at end of property Index: src/mod_accesslog.c =================================================================== --- src/mod_accesslog.c (revision 2989) +++ src/mod_accesslog.c (working copy) @@ -606,13 +606,12 @@ if (-1 != s->log_access_fd) close(s->log_access_fd); if (-1 == (s->log_access_fd = - open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { + open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE | O_CLOEXEC, 0644))) { log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno)); return HANDLER_ERROR; } - fd_close_on_exec(s->log_access_fd); } } Index: src/mod_cgi.c =================================================================== --- src/mod_cgi.c (revision 2989) +++ src/mod_cgi.c (working copy) @@ -986,12 +986,7 @@ } *c = '/'; } - - /* we don't need the client socket */ - for (i = 3; i < 256; i++) { - if (i != srv->errorlog_fd) close(i); - } - + /* we are using *_CLOEXEC */ /* exec the cgi */ execve(args[0], args, env.ptr); @@ -1033,7 +1028,7 @@ if (c->file.mmap.start == MAP_FAILED) { if (-1 == c->file.fd && /* open the file if not already open */ - -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { + -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY | O_CLOEXEC))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); close(from_cgi_fds[0]); Index: src/mod_compress.c =================================================================== --- src/mod_compress.c (revision 2989) +++ src/mod_compress.c (working copy) @@ -7,7 +7,6 @@ #include "plugin.h" #include "crc32.h" -#include "etag.h" #include #include Index: src/mod_dirlisting.c =================================================================== --- src/mod_dirlisting.c (revision 2989) +++ src/mod_dirlisting.c (working copy) @@ -118,7 +118,7 @@ } - if (NULL == (exb->ptr[exb->used]->regex = pcre_compile(string->ptr, 0, + if (NULL == (exb->ptr[exb->used]->regex = pcre_compile(string->ptr, PCRE_UTF8, &errptr, &erroff, NULL))) { return -1; } @@ -645,6 +645,7 @@ size_t k; const char *content_type; long name_max; + size_t dlen; #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) char attrval[128]; int attrlen; @@ -718,6 +719,7 @@ /* compare d_name against excludes array * elements, skipping any that match. */ + dlen = strlen(dent->d_name); #ifdef HAVE_PCRE_H for(i = 0; i < p->conf.excludes->used; i++) { int n; @@ -725,8 +727,8 @@ int ovec[N * 3]; pcre *regex = p->conf.excludes->ptr[i]->regex; - if ((n = pcre_exec(regex, NULL, dent->d_name, - strlen(dent->d_name), 0, 0, ovec, 3 * N)) < 0) { + if ((n = pcre_exec(regex, NULL, dent->d_name, dlen, + 0, 0, ovec, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { log_error_write(srv, __FILE__, __LINE__, "sd", "execution error while matching:", n); @@ -749,14 +751,12 @@ } #endif - i = strlen(dent->d_name); - /* NOTE: the manual says, d_name is never more than NAME_MAX * so this should actually not be a buffer-overflow-risk */ - if (i > (size_t)name_max) continue; + if (dlen > (size_t)name_max) continue; - memcpy(path_file, dent->d_name, i + 1); + memcpy(path_file, dent->d_name, dlen + 1); if (stat(path, &st) != 0) continue; @@ -770,11 +770,11 @@ force_assert(list->ent); } - tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i); + tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + dlen); tmp->mtime = st.st_mtime; tmp->size = st.st_size; - tmp->namelen = i; - memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1); + tmp->namelen = dlen; + memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, dlen + 1); list->ent[list->used++] = tmp; } @@ -944,6 +944,8 @@ } if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON; + /* Must be readable by others */ + if (!(sce->st.st_mode & S_IROTH)) return HANDLER_GO_ON; if (http_list_directory(srv, con, p, con->physical.path)) { /* dirlisting failed */ Index: src/mod_magnet.c =================================================================== --- src/mod_magnet.c (revision 2989) +++ src/mod_magnet.c (working copy) @@ -8,7 +8,6 @@ #include "response.h" #include "stat_cache.h" #include "status_counter.h" -#include "etag.h" #include #include Index: src/mod_rrdtool.c =================================================================== --- src/mod_rrdtool.c (revision 2989) +++ src/mod_rrdtool.c (working copy) @@ -99,15 +99,15 @@ int to_rrdtool_fds[2]; int from_rrdtool_fds[2]; - if (pipe(to_rrdtool_fds)) { + if (pipe2(to_rrdtool_fds, O_CLOEXEC)) { log_error_write(srv, __FILE__, __LINE__, "ss", - "pipe failed: ", strerror(errno)); + "pipe2 failed: ", strerror(errno)); return -1; } - if (pipe(from_rrdtool_fds)) { + if (pipe2(from_rrdtool_fds, O_CLOEXEC)) { log_error_write(srv, __FILE__, __LINE__, "ss", - "pipe failed: ", strerror(errno)); + "pipe2 failed: ", strerror(errno)); return -1; } @@ -122,7 +122,7 @@ /* move stdout to from_rrdtool_fd[1] */ close(STDOUT_FILENO); - dup2(from_rrdtool_fds[1], STDOUT_FILENO); + dup3(from_rrdtool_fds[1], STDOUT_FILENO, O_CLOEXEC); close(from_rrdtool_fds[1]); /* not needed */ close(from_rrdtool_fds[0]); @@ -129,7 +129,7 @@ /* move the stdin to to_rrdtool_fd[0] */ close(STDIN_FILENO); - dup2(to_rrdtool_fds[0], STDIN_FILENO); + dup3(to_rrdtool_fds[0], STDIN_FILENO, O_CLOEXEC); close(to_rrdtool_fds[0]); /* not needed */ close(to_rrdtool_fds[1]); @@ -143,10 +143,12 @@ args[i++] = dash; args[i ] = NULL; +#ifndef FD_CLOEXEC /* we don't need the client socket */ for (i = 3; i < 256; i++) { close(i); } +#endif /* exec the cgi */ execv(args[0], args); @@ -172,9 +174,6 @@ p->read_fd = from_rrdtool_fds[0]; p->rrdtool_pid = pid; - fd_close_on_exec(p->write_fd); - fd_close_on_exec(p->read_fd); - break; } } Index: src/mod_simple_vhost.c =================================================================== --- src/mod_simple_vhost.c (revision 2989) +++ src/mod_simple_vhost.c (working copy) @@ -209,6 +209,8 @@ } } + con->bad_host = 0; + return 0; } #undef PATCH @@ -237,18 +239,18 @@ buffer_copy_buffer(con->physical.doc_root, p->conf.docroot_cache_value); } else { /* build document-root */ - if (buffer_string_is_empty(con->uri.authority) || - build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) { - /* not found, fallback the default-host */ - if (0 == build_doc_root(srv, con, p, - p->doc_root, - p->conf.default_host)) { - /* default host worked */ - buffer_copy_buffer(con->server_name, p->conf.default_host); - buffer_copy_buffer(con->physical.doc_root, p->doc_root); - /* do not cache default host */ + if (buffer_string_is_empty(con->uri.authority)) { + if (build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) { + /* not found */ + con->bad_host = 1; + return HANDLER_GO_ON; } - return HANDLER_GO_ON; + } else { + if (build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) { + /* not found */ + con->bad_host = 1; + return HANDLER_GO_ON; + } } /* found host */ Index: src/mod_ssi.c =================================================================== --- src/mod_ssi.c (revision 2989) +++ src/mod_ssi.c (working copy) @@ -36,7 +36,6 @@ # include #endif -#include "etag.h" #include "version.h" /* The newest modified time of included files for include statement */ Index: src/mod_staticfile.c =================================================================== --- src/mod_staticfile.c (revision 2989) +++ src/mod_staticfile.c (working copy) @@ -1,11 +1,9 @@ #include "base.h" #include "log.h" #include "buffer.h" - +#include "misc.h" #include "plugin.h" - #include "stat_cache.h" -#include "etag.h" #include "http_chunk.h" #include "response.h" @@ -153,12 +151,28 @@ } #undef PATCH +static void makeboundary(char *tp) +{ + int i; + uint32_t tmp; + + for (i = 0; i < 4; i++, tp += 4) { + tmp = get_random32(); + tp[0] = base32[(tmp >> 0) % 32]; + tp[1] = base32[(tmp >> 8) % 32]; + tp[2] = base32[(tmp >> 16) % 32]; + tp[3] = base32[(tmp >> 24) % 32]; + } + tp[0] = 0; +} + static int http_response_parse_range(server *srv, connection *con, plugin_data *p) { int multipart = 0; int error; off_t start, end; const char *s, *minus; - char *boundary = "fkj49sn38dcn3"; + char boundary[16+1]; + int bready = 0; data_string *ds; stat_cache_entry *sce = NULL; buffer *content_type = NULL; @@ -199,6 +213,10 @@ start = sce->st.st_size + le; } else if (*err == ',') { multipart = 1; + if (!bready) { + bready = 1; + makeboundary(boundary); + } s = err + 1; end = sce->st.st_size - 1; @@ -224,6 +242,10 @@ } else if (*(err + 1) == ',') { multipart = 1; s = err + 2; + if (!bready) { + bready = 1; + makeboundary(boundary); + } end = sce->st.st_size - 1; start = la; @@ -256,6 +278,10 @@ } else if (*err == ',') { multipart = 1; s = err + 1; + if (!bready) { + bready = 1; + makeboundary(boundary); + } end = le; start = la; Index: src/network.c =================================================================== --- src/network.c (revision 2989) +++ src/network.c (working copy) @@ -231,7 +231,7 @@ srv_socket->addr.plain.sa_family = AF_UNIX; - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) { + if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))) { log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); goto error_free_socket; } @@ -246,7 +246,7 @@ if (s->use_ipv6) { srv_socket->addr.plain.sa_family = AF_INET6; - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) { + if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP))) { log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); goto error_free_socket; } @@ -255,15 +255,12 @@ if (srv_socket->fd == -1) { srv_socket->addr.plain.sa_family = AF_INET; - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) { + if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP))) { log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); goto error_free_socket; } } - /* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */ - fd_close_on_exec(srv_socket->fd); - /* */ srv->cur_fds = srv_socket->fd; Index: src/network_linux_sendfile.c =================================================================== --- src/network_linux_sendfile.c (revision 2989) +++ src/network_linux_sendfile.c (working copy) @@ -136,12 +136,15 @@ /* open file if not already opened */ if (-1 == c->file.fd) { - if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { + c->file.fd = open(c->file.name->ptr, O_RDONLY | O_CLOEXEC | O_NONBLOCK); + if (-1 == c->file.fd) { + if (errno == EINTR || errno == EWOULDBLOCK) { + r = 0; + break; + } log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); - return -1; } - fd_close_on_exec(c->file.fd); #ifdef HAVE_POSIX_FADVISE /* tell the kernel that we want to stream the file */ if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) { @@ -172,7 +175,7 @@ int oerrno = errno; /* We got an event to write but we wrote nothing * - * - the file shrinked -> error + * - the file shrank -> error * - the remote side closed inbetween -> remote-close */ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { @@ -181,7 +184,7 @@ } if (offset > sce->st.st_size) { - /* file shrinked, close the connection */ + /* file shrank, close the connection */ errno = oerrno; return -1; Index: src/network_openssl.c =================================================================== --- src/network_openssl.c (revision 2989) +++ src/network_openssl.c (working copy) @@ -180,7 +180,7 @@ if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE; - if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { + if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY | O_CLOEXEC))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno)); return -1; Index: src/network_write.c =================================================================== --- src/network_write.c (revision 2989) +++ src/network_write.c (working copy) @@ -103,12 +103,12 @@ if (toSend > max_bytes) toSend = max_bytes; if (offset > sce->st.st_size) { - log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); + log_error_write(srv, __FILE__, __LINE__, "sb", "file has shrunk:", c->file.name); return -1; } - if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { + if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY | O_CLOEXEC))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); return -1; Index: src/network_writev.c =================================================================== --- src/network_writev.c (revision 2989) +++ src/network_writev.c (working copy) @@ -225,12 +225,11 @@ } if (-1 == c->file.fd) { /* open the file if not already open */ - if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { + if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY | O_CLOEXEC))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno)); return -1; } - fd_close_on_exec(c->file.fd); } if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) { Index: src/response.c =================================================================== --- src/response.c (revision 2989) +++ src/response.c (working copy) @@ -97,10 +97,11 @@ /* cache the generated timestamp */ if (srv->cur_ts != srv->last_generated_date_ts) { + struct tm tmp; + buffer_string_prepare_copy(srv->ts_date_str, 255); - - buffer_append_strftime(srv->ts_date_str, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts))); - + gmtime_r(&(srv->cur_ts), &tmp); + buffer_append_strftime(srv->ts_date_str, "%a, %d %b %Y %H:%M:%S GMT", &tmp); srv->last_generated_date_ts = srv->cur_ts; } @@ -470,7 +471,9 @@ /* the docroot plugin should set the doc_root and might also set the physical.path * for us (all vhost-plugins are supposed to set the doc_root) * */ - switch(r = plugins_call_handle_docroot(srv, con)) { + r = plugins_call_handle_docroot(srv, con); + //TRACE("plugins_call_handle_docroot %p bad_host=%d ret=%d", con, con->bad_host, r); + switch(r) { case HANDLER_GO_ON: break; case HANDLER_FINISHED: @@ -541,6 +544,16 @@ } } + /* Hack */ + if (con->bad_host) { + con->http_status = 400; + if (con->conf.log_request_handling) { + log_error_write(srv, __FILE__, __LINE__, "sb", "invalid host", con->uri.authority); + } + buffer_reset(con->physical.path); + return HANDLER_FINISHED; + } + /* * Noone catched away the file from normal path of execution yet (like mod_access) * @@ -646,8 +659,9 @@ buffer_copy_buffer(con->physical.path, srv->tmp_buf); } - if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { - found = S_ISREG(sce->st.st_mode); + if ((HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) && + S_ISREG(sce->st.st_mode)) { + found = (S_IROTH & sce->st.st_mode) ? 1 : 2; break; } @@ -677,8 +691,14 @@ buffer_reset(con->physical.path); return HANDLER_FINISHED; + } else if (found == 2) { + /* permission denied */ + con->http_status = 403; + buffer_reset(con->physical.path); + return HANDLER_FINISHED; } + #ifdef HAVE_LSTAT if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { con->http_status = 403; Index: src/server.c =================================================================== --- src/server.c (revision 2989) +++ src/server.c (working copy) @@ -1067,7 +1067,6 @@ return -1; } - #ifdef HAVE_FORK /* start watcher and workers */ num_childs = srv->srvconf.max_worker; @@ -1184,7 +1183,7 @@ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { if (0 != FAMOpen2(&srv->stat_cache->fam, "lighttpd")) { log_error_write(srv, __FILE__, __LINE__, "s", - "could not open a fam connection, dieing."); + "could not open a fam connection, dying."); return -1; } #ifdef HAVE_FAMNOEXISTS @@ -1191,14 +1190,18 @@ FAMNoExists(&srv->stat_cache->fam); #endif - fdevent_register(srv->ev, FAMCONNECTION_GETFD(&srv->stat_cache->fam), stat_cache_handle_fdevent, NULL); - fdevent_event_set(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(&srv->stat_cache->fam), FDEVENT_IN); + srv->stat_cache->fam_fcce_ndx = -1; + if (fcntl(FAMCONNECTION_GETFD(&(srv->stat_cache->fam)), F_SETFD, FD_CLOEXEC) == -1) { + log_error_write(srv, __FILE__, __LINE__, "ss", "failed to set FD_CLOEXEC for FAM socket:", strerror(errno)); + } + fdevent_register(srv->ev, FAMCONNECTION_GETFD(&(srv->stat_cache->fam)), stat_cache_handle_fdevent, NULL); + fdevent_event_set(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(&(srv->stat_cache->fam)), FDEVENT_IN); } #endif /* get the current number of FDs */ - srv->cur_fds = open("/dev/null", O_RDONLY); + srv->cur_fds = open("/dev/null", O_RDONLY | O_CLOEXEC); close(srv->cur_fds); for (i = 0; i < srv->srv_sockets.used; i++) { Index: src/stat_cache.c =================================================================== --- src/stat_cache.c (revision 2989) +++ src/stat_cache.c (working copy) @@ -1,10 +1,11 @@ #include "log.h" #include "stat_cache.h" #include "fdevent.h" -#include "etag.h" +#include "base.h" #include #include +#include #include #include @@ -146,6 +147,34 @@ free(sce); } +static inline void stat_cache_fill_statfs(stat_cache_entry *sce) +{ + struct statfs sfs; + + if (statfs(sce->name->ptr, &sfs) == 0) { + sce->fs_type = sfs.f_type; + memset(&sce->fs_fsid, 0, sizeof(sce->fs_fsid)); + memcpy(&sce->fs_fsid, &sfs.f_fsid, sizeof(sfs.f_fsid)); + } else { + sce->fs_type = 0; + memset(&sce->fs_fsid, 0, sizeof(sce->fs_fsid)); + } +} + +static inline void stat_cache_fill_fstatfs(stat_cache_entry *sce, int fd) +{ + struct statfs sfs; + + if (fstatfs(fd, &sfs) == 0) { + sce->fs_type = sfs.f_type; + memset(&sce->fs_fsid, 0, sizeof(sce->fs_fsid)); + memcpy(&sce->fs_fsid, &sfs.f_fsid, sizeof(sfs.f_fsid)); + } else { + sce->fs_type = 0; + memset(&sce->fs_fsid, 0, sizeof(sce->fs_fsid)); + } +} + #ifdef HAVE_FAM_H static fam_dir_entry * fam_dir_entry_init(void) { fam_dir_entry *fam_dir = NULL; @@ -375,7 +404,7 @@ stat_cache *sc; struct stat st; size_t k; - int fd; + int fd = -1; struct stat lst; #ifdef DEBUG_STAT_CACHE size_t i; @@ -479,6 +508,7 @@ /* the stat()-cache entry is still ok */ *ret_sce = sce; + etag_create(sce, con->etag_flags); return HANDLER_GO_ON; } } @@ -504,12 +534,18 @@ } /* try to open the file to check if we can read it */ - if (-1 == (fd = open(name->ptr, O_RDONLY))) { + if (-1 == (fd = open(name->ptr, O_RDONLY | O_CLOEXEC))) { return HANDLER_ERROR; } - close(fd); - } + /* must be world-readable */ + if (!(S_IROTH & st.st_mode)) { + close(fd); + errno = EACCES; + return HANDLER_ERROR; + } + } + if (NULL == sce) { #ifdef DEBUG_STAT_CACHE int osize = splaytree_size(sc->files); @@ -539,6 +575,11 @@ sce->st = st; sce->stat_ts = srv->cur_ts; + if (fd != -1) { + stat_cache_fill_fstatfs(sce, fd); + close(fd); + fd = -1; + } /* catch the obvious symlinks * @@ -631,9 +672,9 @@ } } } - etag_create(sce->etag, &(sce->st), con->etag_flags); + etag_create(sce, con->etag_flags); } else if (S_ISDIR(st.st_mode)) { - etag_create(sce->etag, &(sce->st), con->etag_flags); + etag_create(sce, con->etag_flags); } #ifdef HAVE_FAM_H Index: src/stream.c =================================================================== --- src/stream.c (revision 2989) +++ src/stream.c (working copy) @@ -30,7 +30,7 @@ f->size = st.st_size; #ifdef HAVE_MMAP - if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) { + if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY | O_CLOEXEC))) { return -1; }