1#include "network_backends.h"
2
3#if defined(USE_OPENSSL)
4
5#include "network.h"
6#include "log.h"
7
8#include <unistd.h>
9#include <stdlib.h>
10
11#include <errno.h>
12#include <string.h>
13
14#include <openssl/ssl.h>
15#include <openssl/err.h>
16
17#define DBE 0
18
19static int load_next_chunk(server *srv, connection *con, chunkqueue *cq, off_t max_bytes, const char **data, size_t *data_len) {
20	chunk * const c = cq->first;
21
22#define LOCAL_SEND_BUFSIZE (64 * 1024)
23	/* this is a 64k sendbuffer
24	 *
25	 * it has to stay at the same location all the time to satisfy the needs
26	 * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
27	 *
28	 * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
29	 * -> we expect a 64k block to 'leak' in valgrind
30	 * */
31	static char *local_send_buffer = NULL;
32
33	force_assert(NULL != c);
34
35	switch (c->type) {
36	case MEM_CHUNK:
37		{
38			size_t have;
39
40			force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem));
41
42			have = buffer_string_length(c->mem) - c->offset;
43			if ((off_t) have > max_bytes) have = max_bytes;
44
45			*data = c->mem->ptr + c->offset;
46			*data_len = have;
47		}
48		return 0;
49
50	case FILE_CHUNK:
51		Cdbg(DBE, "FILE_CHUNK: c->file.name=%s", c->file.name->ptr);
52		if (NULL == local_send_buffer) {
53			local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
54			force_assert(NULL != local_send_buffer);
55		}
56
57		if (0 != network_open_file_chunk(srv, con, cq)) return -1;
58
59		{
60			off_t offset, toSend;
61
62			force_assert(c->offset >= 0 && c->offset <= c->file.length);
63			offset = c->file.start + c->offset;
64			toSend = c->file.length - c->offset;
65
66			if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
67			if (toSend > max_bytes) toSend = max_bytes;
68
69			if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
70				log_error_write(srv, __FILE__, __LINE__, "ss", "lseek: ", strerror(errno));
71				return -1;
72			}
73			if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) {
74				log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
75				return -1;
76			}
77
78			*data = local_send_buffer;
79			*data_len = toSend;
80		}
81		return 0;
82
83	case SMB_CHUNK:
84		Cdbg(DBE, "SMB_CHUNK: c->file.name=%s", c->file.name->ptr);
85		if (NULL == local_send_buffer) {
86			local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
87			force_assert(NULL != local_send_buffer);
88		}
89
90		if (0 != network_open_file_chunk(srv, con, cq)) return -1;
91
92		{
93			off_t offset, toSend;
94
95			force_assert(c->offset >= 0 && c->offset <= c->file.length);
96			offset = c->file.start + c->offset;
97			toSend = c->file.length - c->offset;
98
99			if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
100			if (toSend > max_bytes) toSend = max_bytes;
101
102			smbc_wrapper_lseek(con, c->file.fd, offset, SEEK_SET );
103
104			Cdbg(DBE, "c->file.fd=[%d], c->file.length=[%lld]", c->file.fd, c->file.length);
105			Cdbg(DBE, "offset=[%lld], toSend=[%lld]", offset, toSend);
106
107			if (-1 == (toSend = (size_t)smbc_wrapper_read(con, c->file.fd, local_send_buffer, (size_t)toSend ))) {
108				log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
109				smbc_wrapper_close(con, c->file.fd);
110				Cdbg(DBE, "ifd =%d, toSend =%d, errno=%s", c->file.fd, toSend, strerror(errno));
111				return -1;
112			}
113
114			*data = local_send_buffer;
115			*data_len = toSend;
116		}
117		return 0;
118	}
119
120	return -1;
121}
122
123
124int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) {
125	/* the remote side closed the connection before without shutdown request
126	 * - IE
127	 * - wget
128	 * if keep-alive is disabled */
129
130	if (con->keep_alive == 0) {
131		SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
132	}
133
134	chunkqueue_remove_finished_chunks(cq);
135
136	while (max_bytes > 0 && NULL != cq->first) {
137		const char *data;
138		size_t data_len;
139		int r;
140
141		if (0 != load_next_chunk(srv, con, cq, max_bytes, &data, &data_len)) return -1;
142
143		/**
144		 * SSL_write man-page
145		 *
146		 * WARNING
147		 *        When an SSL_write() operation has to be repeated because of
148		 *        SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
149		 *        repeated with the same arguments.
150		 */
151
152		ERR_clear_error();
153		r = SSL_write(ssl, data, data_len);
154
155		if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
156			log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
157			return -1;
158		}
159
160		if (r <= 0) {
161			int ssl_r;
162			unsigned long err;
163
164			switch ((ssl_r = SSL_get_error(ssl, r))) {
165			case SSL_ERROR_WANT_WRITE:
166				return 0; /* try again later */
167			case SSL_ERROR_SYSCALL:
168				/* perhaps we have error waiting in our error-queue */
169				if (0 != (err = ERR_get_error())) {
170					do {
171						log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
172								ssl_r, r,
173								ERR_error_string(err, NULL));
174					} while((err = ERR_get_error()));
175				} else if (r == -1) {
176					/* no, but we have errno */
177					switch(errno) {
178					case EPIPE:
179					case ECONNRESET:
180						return -2;
181					default:
182						log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
183								ssl_r, r, errno,
184								strerror(errno));
185						break;
186					}
187				} else {
188					/* neither error-queue nor errno ? */
189					log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
190							ssl_r, r, errno,
191							strerror(errno));
192				}
193				break;
194
195			case SSL_ERROR_ZERO_RETURN:
196				/* clean shutdown on the remote side */
197
198				if (r == 0) return -2;
199
200				/* fall through */
201			default:
202				while((err = ERR_get_error())) {
203					log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
204							ssl_r, r,
205							ERR_error_string(err, NULL));
206				}
207				break;
208			}
209			return -1;
210		}
211
212		chunkqueue_mark_written(cq, r);
213		max_bytes -= r;
214
215		if ((size_t) r < data_len) break; /* try again later */
216	}
217
218	return 0;
219}
220#endif /* USE_OPENSSL */
221