2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
#include "network_backends.h"
|
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
#if defined(USE_OPENSSL)
|
2009-10-11 14:31:42 +00:00
|
|
|
|
|
|
|
#include "network.h"
|
|
|
|
#include "log.h"
|
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2006-10-04 13:26:23 +00:00
|
|
|
# include <openssl/ssl.h>
|
|
|
|
# include <openssl/err.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
static int load_next_chunk(server *srv, connection *con, chunkqueue *cq, off_t max_bytes, const char **data, size_t *data_len) {
|
|
|
|
chunk * const c = cq->first;
|
2005-08-22 10:43:26 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
#define LOCAL_SEND_BUFSIZE (64 * 1024)
|
2005-08-22 10:43:26 +00:00
|
|
|
/* this is a 64k sendbuffer
|
|
|
|
*
|
2006-10-04 13:26:23 +00:00
|
|
|
* it has to stay at the same location all the time to satisfy the needs
|
2005-08-22 10:43:26 +00:00
|
|
|
* of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
|
|
|
|
*
|
|
|
|
* the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
|
|
|
|
* -> we expect a 64k block to 'leak' in valgrind
|
|
|
|
* */
|
|
|
|
static char *local_send_buffer = NULL;
|
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
force_assert(NULL != c);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
switch (c->type) {
|
|
|
|
case MEM_CHUNK:
|
|
|
|
{
|
|
|
|
size_t have;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
have = buffer_string_length(c->mem) - c->offset;
|
|
|
|
if ((off_t) have > max_bytes) have = max_bytes;
|
2011-11-30 18:40:08 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
*data = c->mem->ptr + c->offset;
|
|
|
|
*data_len = have;
|
|
|
|
}
|
|
|
|
return 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
case FILE_CHUNK:
|
|
|
|
if (NULL == local_send_buffer) {
|
|
|
|
local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
|
|
|
|
force_assert(NULL != local_send_buffer);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
if (0 != network_open_file_chunk(srv, con, cq)) return -1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
{
|
|
|
|
off_t offset, toSend;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
force_assert(c->offset >= 0 && c->offset <= c->file.length);
|
|
|
|
offset = c->file.start + c->offset;
|
|
|
|
toSend = c->file.length - c->offset;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
|
|
|
|
if (toSend > max_bytes) toSend = max_bytes;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", "lseek: ", strerror(errno));
|
2005-02-20 14:27:00 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2015-08-22 16:00:59 +00:00
|
|
|
if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
|
|
|
|
return -1;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2005-08-08 08:22:06 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
*data = local_send_buffer;
|
|
|
|
*data_len = toSend;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-08-08 08:22:06 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) {
|
|
|
|
/* the remote side closed the connection before without shutdown request
|
|
|
|
* - IE
|
|
|
|
* - wget
|
|
|
|
* if keep-alive is disabled */
|
2005-08-22 10:43:26 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
if (con->keep_alive == 0) {
|
|
|
|
SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
|
|
|
|
}
|
2005-08-08 08:22:06 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
chunkqueue_remove_finished_chunks(cq);
|
2005-08-22 10:43:26 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
while (max_bytes > 0 && NULL != cq->first) {
|
|
|
|
const char *data;
|
|
|
|
size_t data_len;
|
|
|
|
int r;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
if (0 != load_next_chunk(srv, con, cq, max_bytes, &data, &data_len)) return -1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2011-11-30 18:40:08 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
ERR_clear_error();
|
|
|
|
r = SSL_write(ssl, data, data_len);
|
2011-11-30 18:40:08 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
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;
|
|
|
|
}
|
2005-10-31 08:44:54 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
if (r <= 0) {
|
|
|
|
int ssl_r;
|
|
|
|
unsigned long err;
|
|
|
|
|
|
|
|
switch ((ssl_r = SSL_get_error(ssl, r))) {
|
|
|
|
case SSL_ERROR_WANT_WRITE:
|
|
|
|
return 0; /* try again later */
|
|
|
|
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;
|
2005-08-22 10:43:26 +00:00
|
|
|
default:
|
2015-08-22 16:00:59 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
|
|
|
|
ssl_r, r, errno,
|
|
|
|
strerror(errno));
|
|
|
|
break;
|
2005-08-22 10:43:26 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-08-22 16:00:59 +00:00
|
|
|
/* neither error-queue nor errno ? */
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
|
|
|
|
ssl_r, r, errno,
|
|
|
|
strerror(errno));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2015-08-22 16:00:59 +00:00
|
|
|
break;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
case SSL_ERROR_ZERO_RETURN:
|
|
|
|
/* clean shutdown on the remote side */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
if (r == 0) return -2;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
chunkqueue_mark_written(cq, r);
|
|
|
|
max_bytes -= r;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-08-22 16:00:59 +00:00
|
|
|
if ((size_t) r < data_len) break; /* try again later */
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2005-10-31 08:44:54 +00:00
|
|
|
|
2011-08-22 15:12:28 +00:00
|
|
|
return 0;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2015-08-22 16:00:59 +00:00
|
|
|
#endif /* USE_OPENSSL */
|