Diff for /embedaddon/lighttpd/src/network_openssl.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2014/06/15 20:20:06 version 1.1.1.3, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "network_backends.h"  #include "network_backends.h"
   
#ifdef USE_OPENSSL#if defined(USE_OPENSSL)
   
 #include "network.h"  #include "network.h"
 #include "fdevent.h"  
 #include "log.h"  #include "log.h"
 #include "stat_cache.h"  
   
#include <sys/types.h>#include <unistd.h>
#include <sys/socket.h>#include <stdlib.h>
#include <sys/stat.h> 
#include <sys/time.h> 
#include <sys/resource.h> 
   
 #include <netinet/in.h>  
 #include <netinet/tcp.h>  
   
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  
 #include <unistd.h>  
 #include <netdb.h>  
 #include <string.h>  #include <string.h>
 #include <stdlib.h>  
 #include <assert.h>  
   
 # include <openssl/ssl.h>  # include <openssl/ssl.h>
 # include <openssl/err.h>  # include <openssl/err.h>
   
int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) {static int load_next_chunk(server *srv, connection *con, chunkqueue *cq, off_t max_bytes, const char **data, size_t *data_len) {
        int ssl_r;        chunk * const c = cq->first;
        chunk *c; 
   
   #define LOCAL_SEND_BUFSIZE (64 * 1024)
         /* this is a 64k sendbuffer          /* this is a 64k sendbuffer
          *           *
          * it has to stay at the same location all the time to satisfy the needs           * it has to stay at the same location all the time to satisfy the needs
Line 38  int network_write_chunkqueue_openssl(server *srv, conn Line 27  int network_write_chunkqueue_openssl(server *srv, conn
          *           *
          * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown           * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
          * -> we expect a 64k block to 'leak' in valgrind           * -> we expect a 64k block to 'leak' in valgrind
          *  
          *  
          * In reality we would like to use mmap() but we don't have a guarantee that  
          * we get the same mmap() address for each call. On openbsd the mmap() address  
          * even randomized.  
          *   That means either we keep the mmap() open or we do a read() into a  
          * constant buffer  
          * */           * */
 #define LOCAL_SEND_BUFSIZE (64 * 1024)  
         static char *local_send_buffer = NULL;          static char *local_send_buffer = NULL;
   
        /* the remote side closed the connection before without shutdown request        force_assert(NULL != c);
         * - IE 
         * - wget 
         * if keep-alive is disabled */ 
   
        if (con->keep_alive == 0) {        switch (c->type) {
                SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);        case MEM_CHUNK:
        }                {
                         size_t have;
   
        for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {                        force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem));
                int chunk_finished = 0; 
   
                switch(c->type) {                        have = buffer_string_length(c->mem) - c->offset;
                case MEM_CHUNK: {                        if ((off_t) have > max_bytes) have = max_bytes;
                        char * offset; 
                        off_t toSend; 
                        ssize_t r; 
   
                        if (c->mem->used == 0 || c->mem->used == 1) {                        *data = c->mem->ptr + c->offset;
                                chunk_finished = 1;                        *data_len = have;
                                break;                }
                        }                return 0;
   
                        offset = c->mem->ptr + c->offset;        case FILE_CHUNK:
                        toSend = c->mem->used - 1 - c->offset;                if (NULL == local_send_buffer) {
                        if (toSend > max_bytes) toSend = max_bytes;                        local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
                         force_assert(NULL != local_send_buffer);
                 }
   
                        /**                if (0 != network_open_file_chunk(srv, con, cq)) return -1;
                         * SSL_write man-page 
                         * 
                         * WARNING 
                         *        When an SSL_write() operation has to be repeated because of 
                         *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be 
                         *        repeated with the same arguments. 
                         * 
                         */ 
   
                        ERR_clear_error();                {
                        r = SSL_write(ssl, offset, toSend);                        off_t offset, toSend;
   
                        if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {                        force_assert(c->offset >= 0 && c->offset <= c->file.length);
                                log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");                        offset = c->file.start + c->offset;
                                return -1;                        toSend = c->file.length - c->offset;
                        } 
   
                        if (r <= 0) {                        if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
                                unsigned long err;                        if (toSend > max_bytes) toSend = max_bytes;
   
                                switch ((ssl_r = SSL_get_error(ssl, r))) {                        if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
                                case SSL_ERROR_WANT_WRITE:                                log_error_write(srv, __FILE__, __LINE__, "ss", "lseek: ", strerror(errno));
                                        break;                                return -1;
                                case SSL_ERROR_SYSCALL: 
                                        /* perhaps we have error waiting in our error-queue */ 
                                        if (0 != (err = ERR_get_error())) { 
                                                do { 
                                                        log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
                                                                        ssl_r, r, 
                                                                        ERR_error_string(err, NULL)); 
                                                } while((err = ERR_get_error())); 
                                        } else if (r == -1) { 
                                                /* no, but we have errno */ 
                                                switch(errno) { 
                                                case EPIPE: 
                                                case ECONNRESET: 
                                                        return -2; 
                                                default: 
                                                        log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
                                                                        ssl_r, r, errno, 
                                                                        strerror(errno)); 
                                                        break; 
                                                } 
                                        } else { 
                                                /* neither error-queue nor errno ? */ 
                                                log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
                                                                ssl_r, r, errno, 
                                                                strerror(errno)); 
                                        } 
 
                                        return  -1; 
                                case SSL_ERROR_ZERO_RETURN: 
                                        /* clean shutdown on the remote side */ 
 
                                        if (r == 0) return -2; 
 
                                        /* fall through */ 
                                default: 
                                        while((err = ERR_get_error())) { 
                                                log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", 
                                                                ssl_r, r, 
                                                                ERR_error_string(err, NULL)); 
                                        } 
 
                                        return  -1; 
                                } 
                        } else { 
                                c->offset += r; 
                                cq->bytes_out += r; 
                                max_bytes -= r; 
                         }                          }
                        if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) {
                        if (c->offset == (off_t)c->mem->used - 1) {                                log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
                                chunk_finished = 1;                                return -1;
                         }                          }
   
                        break;                        *data = local_send_buffer;
                         *data_len = toSend;
                 }                  }
                case FILE_CHUNK: {                return 0;
                        char *s;        }
                        ssize_t r; 
                        stat_cache_entry *sce = NULL; 
                        int ifd; 
                        int write_wait = 0; 
   
                        if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {        return -1;
                                log_error_write(srv, __FILE__, __LINE__, "sb",}
                                                strerror(errno), c->file.name); 
                                return -1; 
                        } 
   
                         if (NULL == local_send_buffer) {  
                                 local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);  
                                 force_assert(local_send_buffer);  
                         }  
   
                        do {int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) {
                                off_t offset = c->file.start + c->offset;        /* the remote side closed the connection before without shutdown request
                                off_t toSend = c->file.length - c->offset;         * - IE
                                if (toSend > max_bytes) toSend = max_bytes;         * - wget
          * if keep-alive is disabled */
   
                                if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;        if (con->keep_alive == 0) {
                 SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
         }
   
                                if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {        chunkqueue_remove_finished_chunks(cq);
                                        log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno)); 
   
                                        return -1;        while (max_bytes > 0 && NULL != cq->first) {
                                }                const char *data;
                 size_t data_len;
                 int r;
   
                   if (0 != load_next_chunk(srv, con, cq, max_bytes, &data, &data_len)) return -1;
   
                                if (-1 == lseek(ifd, offset, SEEK_SET)) {                /**
                                        log_error_write(srv, __FILE__, __LINE__, "ss", "lseek failed:", strerror(errno));                 * SSL_write man-page
                                        close(ifd);                 *
                                        return -1;                 * WARNING
                                }                 *        When an SSL_write() operation has to be repeated because of
                                if (-1 == (toSend = read(ifd, local_send_buffer, toSend))) {                 *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
                                        log_error_write(srv, __FILE__, __LINE__, "ss", "read failed:", strerror(errno));                 *        repeated with the same arguments.
                                        close(ifd);                 */
                                        return -1; 
                                } 
   
                                s = local_send_buffer;                ERR_clear_error();
                 r = SSL_write(ssl, data, data_len);
   
                                close(ifd);                if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
                         log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
                         return -1;
                 }
   
                                ERR_clear_error();                if (r <= 0) {
                                r = SSL_write(ssl, s, toSend);                        int ssl_r;
                         unsigned long err;
   
                                if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {                        switch ((ssl_r = SSL_get_error(ssl, r))) {
                                        log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");                        case SSL_ERROR_WANT_READ:
                                        return -1;                                con->is_readable = -1;
                                }                                return 0; /* try again later */
                        case SSL_ERROR_WANT_WRITE:
                                if (r <= 0) {                                con->is_writable = -1;
                                        unsigned long err;                                return 0; /* try again later */
                        case SSL_ERROR_SYSCALL:
                                        switch ((ssl_r = SSL_get_error(ssl, r))) {                                /* perhaps we have error waiting in our error-queue */
                                        case SSL_ERROR_WANT_WRITE:                                if (0 != (err = ERR_get_error())) {
                                                write_wait = 1;                                        do {
                                                break;                                                log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
                                        case SSL_ERROR_SYSCALL:                                                                ssl_r, r,
                                                /* perhaps we have error waiting in our error-queue */                                                                ERR_error_string(err, NULL));
                                                if (0 != (err = ERR_get_error())) {                                        } while((err = ERR_get_error()));
                                                        do {                                } else if (r == -1) {
                                                                log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",                                        /* no, but we have errno */
                                                                                ssl_r, r,                                        switch(errno) {
                                                                                ERR_error_string(err, NULL));                                        case EPIPE:
                                                        } while((err = ERR_get_error()));                                        case ECONNRESET:
                                                } else if (r == -1) {                                                return -2;
                                                        /* no, but we have errno */ 
                                                        switch(errno) { 
                                                        case EPIPE: 
                                                        case ECONNRESET: 
                                                                return -2; 
                                                        default: 
                                                                log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", 
                                                                                ssl_r, r, errno, 
                                                                                strerror(errno)); 
                                                                break; 
                                                        } 
                                                } else { 
                                                        /* neither error-queue nor errno ? */ 
                                                        log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", 
                                                                        ssl_r, r, errno, 
                                                                        strerror(errno)); 
                                                } 
 
                                                return  -1; 
                                        case SSL_ERROR_ZERO_RETURN: 
                                                /* clean shutdown on the remote side */ 
 
                                                if (r == 0)  return -2; 
 
                                                /* fall thourgh */ 
                                         default:                                          default:
                                                while((err = ERR_get_error())) {                                                log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
                                                        log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",                                                                ssl_r, r, errno,
                                                                        ssl_r, r,                                                                strerror(errno));
                                                                        ERR_error_string(err, NULL));                                                break;
                                                } 
 
                                                return -1; 
                                         }                                          }
                                 } else {                                  } else {
                                        c->offset += r;                                        /* neither error-queue nor errno ? */
                                        cq->bytes_out += r;                                        log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
                                        max_bytes -= r;                                                        ssl_r, r, errno,
                                                         strerror(errno));
                                 }                                  }
                                   break;
   
                                if (c->offset == c->file.length) {                        case SSL_ERROR_ZERO_RETURN:
                                        chunk_finished = 1;                                /* clean shutdown on the remote side */
                                } 
                        } while (!chunk_finished && !write_wait && max_bytes > 0); 
   
                        break;                                if (r == 0) return -2;
                } 
                default: 
                        log_error_write(srv, __FILE__, __LINE__, "s", "type not known"); 
   
                                   /* fall through */
                           default:
                                   while((err = ERR_get_error())) {
                                           log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
                                                           ssl_r, r,
                                                           ERR_error_string(err, NULL));
                                   }
                                   break;
                           }
                         return -1;                          return -1;
                 }                  }
   
                if (!chunk_finished) {                chunkqueue_mark_written(cq, r);
                        /* not finished yet */                max_bytes -= r;
   
                        break;                if ((size_t) r < data_len) break; /* try again later */
                } 
         }          }
   
         return 0;          return 0;
 }  }
#endif#endif /* USE_OPENSSL */
 
#if 0 
network_openssl_init(void) { 
        p->write_ssl = network_openssl_write_chunkset; 
} 
#endif 

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>