1 /*
2 * ProFTPD: mod_deflate -- a module for supporting on-the-fly compression
3 * Copyright (c) 2004-2017 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 *
24 * This is mod_deflate, contrib software for proftpd 1.3.x and above.
25 * For more information contact TJ Saunders <tj@castaglia.org>.
26 *
27 * $Libraries: -lz$
28 */
29
30 #include <zlib.h>
31
32 #include "conf.h"
33 #include "privs.h"
34
35 #define MOD_DEFLATE_VERSION "mod_deflate/0.6"
36
37 /* Make sure the version of proftpd is as necessary. */
38 #if PROFTPD_VERSION_NUMBER < 0x0001030604
39 # error "ProFTPD 1.3.6 or later required"
40 #endif
41
42 module deflate_module;
43
44 static int deflate_sess_init(void);
45
46 static int deflate_enabled = FALSE;
47 static int deflate_engine = FALSE;
48 static int deflate_logfd = -1;
49 static pr_netio_t *deflate_netio = NULL;
50 static pr_netio_t *deflate_next_netio = NULL;
51
52 /* These are for tracking the callbacks of the next NetIO, if any, that we
53 * override, for restoring later via OPTS.
54 */
55 static int (*deflate_next_netio_close)(pr_netio_stream_t *) = NULL;
56 static pr_netio_stream_t *(*deflate_next_netio_open)(pr_netio_stream_t *, int, int) = NULL;
57 static int (*deflate_next_netio_read)(pr_netio_stream_t *, char *, size_t) = NULL;
58 static int (*deflate_next_netio_shutdown)(pr_netio_stream_t *, int) = NULL;
59 static int (*deflate_next_netio_write)(pr_netio_stream_t *, char *, size_t) = NULL;
60
61 /* Draft-recommended ZLIB defaults:
62 *
63 * The following ZLIB [5] parameters are recommended for deflate
64 * transmission mode:
65 *
66 * Compression level: 7
67 * Compression method: Z_DEFLATED
68 * Window bits: -15
69 * Memory level: 8
70 * Strategy: Z_DEFAULT_STRATEGY
71 */
72
73 #define MOD_DEFLATE_DEFAULT_COMPRESS_LEVEL 7
74 static int deflate_compression_level = MOD_DEFLATE_DEFAULT_COMPRESS_LEVEL;
75
76 #define MOD_DEFLATE_DEFAULT_MEM_LEVEL 8
77 static int deflate_mem_level = MOD_DEFLATE_DEFAULT_MEM_LEVEL;
78
79 #define MOD_DEFLATE_DEFAULT_STRATEGY Z_DEFAULT_STRATEGY
80 static int deflate_strategy = MOD_DEFLATE_DEFAULT_STRATEGY;
81
82 #define MOD_DEFLATE_DEFAULT_WINDOW_BITS 15
83 static int deflate_window_bits = MOD_DEFLATE_DEFAULT_WINDOW_BITS;
84
85 /* The _ptr pointer always points to the start of the buffer; the _zbuf
86 * pointer points to the current place within the buffer from which to read
87 * data.
88 */
89 static Byte *deflate_zbuf_ptr = NULL;
90 static Byte *deflate_zbuf = NULL;
91 static size_t deflate_zbuflen = 0;
92 static size_t deflate_zbufsz = 0;
93
94 static Byte *deflate_rbuf = NULL;
95 static size_t deflate_rbuflen = 0;
96 static size_t deflate_rbufsz = 0;
97
98 #define DEFLATE_NETIO_NOTE "mod_deflate.z_stream"
99 static int deflate_zerrno = 0;
100
101 static const char *trace_channel = "deflate";
102
deflate_zstrerror(int zerrno)103 static const char *deflate_zstrerror(int zerrno) {
104 const char *zstr = "unknown";
105
106 switch (zerrno) {
107 case Z_OK:
108 zstr = "OK";
109 break;
110
111 case Z_STREAM_END:
112 return "End of stream";
113 break;
114
115 case Z_NEED_DICT:
116 return "Need dictionary";
117 break;
118
119 case Z_ERRNO:
120 zstr = strerror(errno);
121 break;
122
123 case Z_DATA_ERROR:
124 zstr = "Data error";
125 break;
126
127 case Z_MEM_ERROR:
128 zstr = "Memory error";
129 break;
130
131 case Z_BUF_ERROR:
132 zstr = "Buffer error";
133 break;
134
135 case Z_VERSION_ERROR:
136 zstr = "Version error";
137 break;
138 }
139
140 return zstr;
141 }
142
143 /* NetIO callbacks
144 */
145
deflate_netio_close_cb(pr_netio_stream_t * nstrm)146 static int deflate_netio_close_cb(pr_netio_stream_t *nstrm) {
147 int res = 0;
148
149 if (nstrm->strm_type == PR_NETIO_STRM_DATA) {
150 z_stream *zstrm;
151
152 zstrm = (z_stream *) pr_table_get(nstrm->notes, DEFLATE_NETIO_NOTE, NULL);
153 if (zstrm == NULL) {
154 int xerrno = 0;
155
156 res = 0;
157
158 if (deflate_next_netio_close != NULL) {
159 res = (deflate_next_netio_close)(nstrm);
160 xerrno = errno;
161
162 if (res < 0) {
163 pr_trace_msg(trace_channel, 1, "error calling next netio close: %s",
164 strerror(xerrno));
165 }
166 }
167
168 errno = xerrno;
169 return res;
170 }
171
172 if (nstrm->strm_mode == PR_NETIO_IO_WR) {
173 if (zstrm->total_in > 0) {
174 float ratio;
175
176 ratio = ((float) zstrm->total_out / (float) zstrm->total_in);
177
178 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
179 "%s: deflated %lu bytes to %lu bytes (%0.2lf%% compression)",
180 session.curr_cmd, zstrm->total_in, zstrm->total_out,
181 (1.0 - ratio) * 100.0);
182 }
183
184 res = deflateEnd(zstrm);
185 if (res != Z_OK) {
186 pr_trace_msg(trace_channel, 3,
187 "close: error closing deflating netio: [%d] %s", res,
188 zstrm->msg ? zstrm->msg : deflate_zstrerror(res));
189
190 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
191 "error closing deflating netio: [%d] %s", res,
192 zstrm->msg ? zstrm->msg : deflate_zstrerror(res));
193 }
194
195 } else if (nstrm->strm_mode == PR_NETIO_IO_RD) {
196 if (zstrm->total_in > 0) {
197 float ratio;
198
199 ratio = ((float) zstrm->total_in / (float) zstrm->total_out);
200
201 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
202 "%s: inflated %lu bytes to %lu bytes (%0.2lf%% compression)",
203 session.curr_cmd, zstrm->total_in, zstrm->total_out,
204 (1.0 - ratio) * 100.0);
205 }
206
207 res = inflateEnd(zstrm);
208 if (res != Z_OK) {
209 pr_trace_msg(trace_channel, 3,
210 "close: error closing inflating netio: [%d] %s", res,
211 zstrm->msg ? zstrm->msg : deflate_zstrerror(res));
212
213 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
214 "error closing inflating netio: [%d] %s", res,
215 zstrm->msg ? zstrm->msg : deflate_zstrerror(res));
216 }
217 }
218
219 if (deflate_next_netio == NULL) {
220 res = close(nstrm->strm_fd);
221 nstrm->strm_fd = -1;
222 }
223
224 pr_table_remove(nstrm->notes, DEFLATE_NETIO_NOTE, NULL);
225 }
226
227 if (deflate_next_netio_close != NULL) {
228 if ((deflate_next_netio_close)(nstrm) < 0) {
229 pr_trace_msg(trace_channel, 1, "error calling next netio close: %s",
230 strerror(errno));
231 }
232 }
233
234 return res;
235 }
236
deflate_netio_open_cb(pr_netio_stream_t * nstrm,int fd,int mode)237 static pr_netio_stream_t *deflate_netio_open_cb(pr_netio_stream_t *nstrm,
238 int fd, int mode) {
239
240 nstrm->strm_fd = fd;
241 nstrm->strm_mode = mode;
242
243 if (deflate_next_netio_open != NULL) {
244 if ((deflate_next_netio_open)(nstrm, fd, mode) == NULL) {
245 int xerrno = errno;
246
247 pr_trace_msg(trace_channel, 1, "error calling next netio open: %s",
248 strerror(xerrno));
249 errno = xerrno;
250 return NULL;
251 }
252 }
253
254 if (nstrm->strm_type == PR_NETIO_STRM_DATA) {
255 int res;
256 z_stream *zstrm;
257
258 /* Set the initial ZLIB parameters. */
259 zstrm = pcalloc(nstrm->strm_pool, sizeof(z_stream));
260 zstrm->zalloc = Z_NULL;
261 zstrm->zfree = Z_NULL;
262 zstrm->opaque = Z_NULL;
263 zstrm->next_in = Z_NULL;
264 zstrm->next_out = Z_NULL;
265 zstrm->avail_in = 0;
266 zstrm->avail_out = 0;
267
268 if (pr_table_add(nstrm->notes,
269 pstrdup(nstrm->strm_pool, DEFLATE_NETIO_NOTE), zstrm,
270 sizeof(z_stream *)) < 0) {
271 if (errno != EEXIST) {
272 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
273 "error stashing '%s' note: %s", DEFLATE_NETIO_NOTE, strerror(errno));
274 }
275 }
276
277 memset(deflate_zbuf_ptr, '\0', deflate_zbufsz);
278 deflate_zbuf = deflate_zbuf_ptr;
279
280 if (nstrm->strm_mode == PR_NETIO_IO_WR) {
281 /* Initialize the zlib data for deflation. */
282 res = deflateInit2(zstrm, deflate_compression_level, Z_DEFLATED,
283 deflate_window_bits, deflate_mem_level, deflate_strategy);
284
285 switch (res) {
286 case Z_OK:
287 zstrm->next_out = deflate_zbuf;
288 zstrm->avail_out = deflate_zbufsz;
289 break;
290
291 case Z_MEM_ERROR:
292 case Z_STREAM_ERROR:
293 pr_trace_msg(trace_channel, 3,
294 "open: error initializing for deflation: [%d] %s", res,
295 zstrm->msg ? zstrm->msg : deflate_zstrerror(res));
296
297 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
298 "error initializing for deflation: [%d] %s", res,
299 zstrm->msg ? zstrm->msg : deflate_zstrerror(res));
300
301 errno = EINVAL;
302 return NULL;
303 }
304
305 } else if (nstrm->strm_mode == PR_NETIO_IO_RD) {
306 /* Initialize the zlib data for inflation.
307 *
308 * The magic number 32 here from the zlib.h documentation; it enables
309 * the automatic header detection of zlib/gzip headers.
310 */
311 res = inflateInit2(zstrm, deflate_window_bits + 32);
312
313 switch (res) {
314 case Z_OK:
315 zstrm->next_out = deflate_zbuf;
316 zstrm->avail_out = deflate_zbufsz;
317 break;
318
319 case Z_MEM_ERROR:
320 case Z_STREAM_ERROR:
321 pr_trace_msg(trace_channel, 3,
322 "open: error initializing for inflation: [%d] %s", res,
323 zstrm->msg ? zstrm->msg : deflate_zstrerror(res));
324
325 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
326 "error initializing for inflation: [%d] %s", res,
327 zstrm->msg ? zstrm->msg : deflate_zstrerror(res));
328
329 errno = EINVAL;
330 return NULL;
331 }
332
333 /* These are used by the read callback; ensure they are initialised to
334 * zero before every read data transfer.
335 */
336 deflate_rbuflen = 0;
337 deflate_zbuflen = 0;
338 }
339 }
340
341 return nstrm;
342 }
343
deflate_netio_read_cb(pr_netio_stream_t * nstrm,char * buf,size_t bufsz)344 static int deflate_netio_read_cb(pr_netio_stream_t *nstrm, char *buf,
345 size_t bufsz) {
346
347 if (bufsz == 0) {
348 return 0;
349 }
350
351 if (nstrm->strm_type == PR_NETIO_STRM_DATA) {
352 int datalen = 0, nread = 0, res, xerrno;
353 size_t copylen = 0;
354 z_stream *zstrm;
355
356 zstrm = (z_stream *) pr_table_get(nstrm->notes, DEFLATE_NETIO_NOTE, NULL);
357 if (zstrm == NULL) {
358 pr_trace_msg(trace_channel, 2,
359 "no zstream found in stream data for reading");
360 errno = EIO;
361 return -1;
362 }
363
364 res = 0;
365
366 /* If we have data leftover in deflate_zbuf, start by copying all of that
367 * into the provided buffer. Only read more data from the network and
368 * inflate it when there's no leftover data.
369 */
370
371 if (deflate_zbuflen > 0) {
372 if (bufsz >= deflate_zbuflen) {
373 /* Excellent. We can consume all of the data in the deflate_zbuf
374 * buffer.
375 */
376
377 pr_trace_msg(trace_channel, 9, "read: returning %lu bytes of "
378 "previously uncompressed data; no data read from client",
379 (unsigned long) deflate_zbuflen);
380
381 memcpy(buf, deflate_zbuf, deflate_zbuflen);
382 res = deflate_zbuflen;
383
384 /* Reset the pointer to the start of the buffer. */
385 deflate_zbuf = deflate_zbuf_ptr;
386 deflate_zbuflen = 0;
387
388 /* Manually adjust the "raw" bytes in counter, so that it will
389 * be accurate for %I logging.
390 *
391 * We subtract the number we are returning here, since our return
392 * value will simply be added back to the counter in pr_netio_read().
393 * And if our subtraction causes an underflow, it's still OK since
394 * the subsequent addition will overflow, and get the value back to
395 * what it should be.
396 */
397 session.total_raw_in -= res;
398
399 return res;
400 }
401
402 /* The given buffer can't hold all of our already-inflated data; but
403 * maybe it can hold some of it?
404 */
405
406 pr_trace_msg(trace_channel, 9, "read: returning %lu bytes of previously "
407 "uncompressed data (of %lu bytes total); no data read from client",
408 (unsigned long) bufsz, (unsigned long) deflate_zbuflen);
409
410 memcpy(buf, deflate_zbuf, bufsz);
411 res = bufsz;
412
413 deflate_zbuf += bufsz;
414 deflate_zbuflen -= bufsz;
415
416 /* Manually adjust the "raw" bytes in counter, so that it will
417 * be accurate for %I logging.
418 *
419 * We subtract the number we are returning here, since our return
420 * value will simply be added back to the counter in pr_netio_read().
421 * And if our subtraction causes an underflow, it's still OK since
422 * the subsequent addition will overflow, and get the value back to
423 * what it should be.
424 */
425 session.total_raw_in -= res;
426
427 return res;
428 }
429
430 /* If we reach this point, then the deflate_zbuf buffer is empty of
431 * uncompressed data. We might have some compressed data left over from
432 * the previous inflate() call that we need to process
433 * (i.e. zstrm->avail_in > 0), though.
434 *
435 * Try to read more deta in from the network. If we get no data, AND
436 * zstrm->avail_in is zero, then we've reached EOF. Otherwise, add the
437 * new data to the inflator, and see if we can make some progress.
438 */
439
440 datalen = deflate_rbufsz - deflate_rbuflen;
441
442 if (deflate_next_netio_read != NULL) {
443 nread = (deflate_next_netio_read)(nstrm, (char *) deflate_rbuf, datalen);
444
445 } else {
446 /* Read in some data from the stream's fd. */
447 nread = read(nstrm->strm_fd, deflate_rbuf, datalen);
448 }
449
450 if (nread < 0) {
451 xerrno = errno;
452
453 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
454 "error reading from socket %d: %s", nstrm->strm_fd, strerror(xerrno));
455
456 errno = xerrno;
457 return -1;
458 }
459
460 if (nread == 0) {
461 if (zstrm->avail_in == 0) {
462 /* EOF. We know we can return zero here because the deflate_zbuf
463 * is empty (see above comment), and we haven't read any more data
464 * in from the network.
465 */
466 pr_trace_msg(trace_channel, 8,
467 "read: read EOF from client, returning 0");
468 return 0;
469 }
470 }
471
472 pr_trace_msg(trace_channel, 9,
473 "read: read %d bytes of compressed data from client", nread);
474
475 /* Manually adjust the "raw" bytes in counter, so that it will
476 * be accurate for %I logging.
477 */
478 session.total_raw_in += nread;
479
480 if (zstrm->avail_in > 0) {
481 pr_trace_msg(trace_channel, 9,
482 "read: processing %d bytes of leftover compressed data from client, "
483 "plus %d additional new bytes from client", zstrm->avail_in, nread);
484
485 } else {
486 pr_trace_msg(trace_channel, 9, "read: processing %d bytes from client",
487 nread);
488 }
489
490 datalen = nread;
491 zstrm->next_in = deflate_rbuf;
492 zstrm->avail_in += datalen;
493
494 copylen = 0;
495
496 zstrm->next_out = deflate_zbuf;
497 zstrm->avail_out = deflate_zbufsz;
498
499 pr_trace_msg(trace_channel, 19,
500 "read: pre-inflate zstream state: avail_in = %d, avail_out = %d",
501 zstrm->avail_in, zstrm->avail_out);
502
503 deflate_zerrno = inflate(zstrm, Z_SYNC_FLUSH);
504 xerrno = errno;
505
506 pr_trace_msg(trace_channel, 19,
507 "read: post-inflate zstream state: avail_in = %d, avail_out = %d "
508 "(zerrno = %s)", zstrm->avail_in, zstrm->avail_out,
509 deflate_zstrerror(deflate_zerrno));
510
511 errno = xerrno;
512
513 switch (deflate_zerrno) {
514 case Z_OK:
515 case Z_STREAM_END:
516 copylen = deflate_zbufsz - zstrm->avail_out;
517
518 /* Allocate more space for the data if necessary. */
519 if ((deflate_zbuflen + copylen) > deflate_zbufsz) {
520 size_t new_bufsz;
521 Byte *tmp;
522
523 new_bufsz = deflate_zbufsz;
524 while ((deflate_zbuflen + copylen) > new_bufsz) {
525 pr_signals_handle();
526 new_bufsz *= 2;
527 }
528
529 pr_trace_msg(trace_channel, 9,
530 "read: allocated new deflate buffer (size %lu)",
531 (unsigned long) new_bufsz);
532
533 tmp = palloc(session.pool, new_bufsz);
534 memcpy(tmp, deflate_zbuf, deflate_zbuflen);
535
536 deflate_zbuf_ptr = deflate_zbuf = tmp;
537 deflate_zbufsz = new_bufsz;
538 }
539
540 break;
541
542 default:
543 pr_trace_msg(trace_channel, 3,
544 "read: error inflating %lu bytes of data: [%d] %s: %s",
545 (unsigned long) datalen, deflate_zerrno,
546 deflate_zstrerror(deflate_zerrno),
547 zstrm->msg ? zstrm->msg : "unavailable");
548
549 errno = xerrno;
550 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
551 "error inflating %lu bytes of data: [%d] %s",
552 (unsigned long) datalen, deflate_zerrno,
553 zstrm->msg ? zstrm->msg : deflate_zstrerror(deflate_zerrno));
554
555 errno = EIO;
556 return -1;
557 }
558
559 deflate_zbuflen = deflate_zbufsz - zstrm->avail_out;
560
561 /* Now all we have to do is return EAGAIN, so that the FSIO API calls
562 * us back immediately. That will hit the check for deflate_zbuflen
563 * earlier in this function, and return the data we just decompressed.
564 */
565 errno = EAGAIN;
566 return -1;
567 }
568
569 return read(nstrm->strm_fd, buf, bufsz);
570 }
571
deflate_netio_shutdown_cb(pr_netio_stream_t * nstrm,int how)572 static int deflate_netio_shutdown_cb(pr_netio_stream_t *nstrm, int how) {
573
574 if (nstrm->strm_type == PR_NETIO_STRM_DATA) {
575 int res = 0;
576 z_stream *zstrm;
577
578 zstrm = (z_stream *) pr_table_get(nstrm->notes, DEFLATE_NETIO_NOTE, NULL);
579 if (zstrm == NULL) {
580 return 0;
581 }
582
583 if (nstrm->strm_mode == PR_NETIO_IO_WR) {
584 zstrm->next_in = Z_NULL;
585 zstrm->avail_in = 0;
586
587 pr_trace_msg(trace_channel, 19,
588 "shutdown: pre-deflate zstream state: avail_in = %d, avail_out = %d",
589 zstrm->avail_in, zstrm->avail_out);
590
591 deflate_zerrno = deflate(zstrm, Z_FINISH);
592
593 pr_trace_msg(trace_channel, 19,
594 "shutdown: post-inflate zstream state: avail_in = %d, avail_out = %d "
595 "(zerrno = %s)", zstrm->avail_in, zstrm->avail_out,
596 deflate_zstrerror(deflate_zerrno));
597
598 if (deflate_zerrno != Z_OK &&
599 deflate_zerrno != Z_STREAM_END) {
600 pr_trace_msg(trace_channel, 3,
601 "shutdown: error deflating data: [%d] %s: %s", deflate_zerrno,
602 deflate_zstrerror(deflate_zerrno),
603 zstrm->msg ? zstrm->msg : "unavailable");
604
605 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
606 "error deflating data: [%d] %s", deflate_zerrno,
607 zstrm->msg ? zstrm->msg : deflate_zstrerror(deflate_zerrno));
608
609 } else {
610 size_t datalen, offset;
611
612 datalen = deflate_zbufsz - zstrm->avail_out;
613 offset = 0;
614
615 while (datalen > 0) {
616 if (deflate_next_netio_write != NULL) {
617 res = (deflate_next_netio_write)(nstrm,
618 (char *) (deflate_zbuf + offset), datalen);
619
620 } else {
621 res = write(nstrm->strm_fd, deflate_zbuf + offset, datalen);
622 }
623
624 if (res < 0) {
625 if (errno == EINTR ||
626 errno == EAGAIN) {
627 /* The socket might be busy, especially if the peer is a bit
628 * slow in reading data from it.
629 */
630 pr_signals_handle();
631 continue;
632 }
633
634 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
635 "error writing to socket %d: %s", nstrm->strm_fd,
636 strerror(errno));
637 return -1;
638 }
639
640 /* Manually update the "raw" bytes counter, so that it will be
641 * accurate for %O logging.
642 */
643 session.total_raw_out += res;
644
645 /* Watch out for short writes. */
646 if ((size_t) res == datalen) {
647 break;
648 }
649
650 offset += res;
651 datalen -= res;
652 }
653 }
654
655 if (deflate_next_netio_shutdown != NULL) {
656 res = (deflate_next_netio_shutdown)(nstrm, how);
657
658 } else {
659 res = shutdown(nstrm->strm_fd, how);
660 }
661
662 return res;
663 }
664 }
665
666 return shutdown(nstrm->strm_fd, how);
667 }
668
deflate_netio_write_cb(pr_netio_stream_t * nstrm,char * buf,size_t buflen)669 static int deflate_netio_write_cb(pr_netio_stream_t *nstrm, char *buf,
670 size_t buflen) {
671
672 if (buflen == 0) {
673 return 0;
674 }
675
676 if (nstrm->strm_type == PR_NETIO_STRM_DATA) {
677 int res = 0, xerrno;
678 size_t datalen, offset = 0;
679 z_stream *zstrm;
680
681 zstrm = (z_stream *) pr_table_get(nstrm->notes, DEFLATE_NETIO_NOTE, NULL);
682 if (zstrm == NULL) {
683 pr_trace_msg(trace_channel, 2,
684 "no zstream found in stream data for writing");
685 errno = EIO;
686 return -1;
687 }
688
689 /* Deflate the data to be written out. */
690 zstrm->next_in = (Bytef *) buf;
691 zstrm->avail_in = buflen;
692
693 pr_trace_msg(trace_channel, 19,
694 "write: pre-deflate zstream state: avail_in = %d, avail_out = %d",
695 zstrm->avail_in, zstrm->avail_out);
696
697 deflate_zerrno = deflate(zstrm, Z_SYNC_FLUSH);
698 xerrno = errno;
699
700 pr_trace_msg(trace_channel, 19,
701 "write: post-inflate zstream state: avail_in = %d, avail_out = %d "
702 "(zerrno = %s)", zstrm->avail_in, zstrm->avail_out,
703 deflate_zstrerror(deflate_zerrno));
704
705 errno = xerrno;
706
707 if (deflate_zerrno != Z_OK) {
708 pr_trace_msg(trace_channel, 3, "write: error deflating data: [%d] %s: %s",
709 deflate_zerrno, deflate_zstrerror(deflate_zerrno),
710 zstrm->msg ? zstrm->msg : "unavailable");
711
712 errno = xerrno;
713
714 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
715 "error deflating data: [%d] %s", deflate_zerrno,
716 zstrm->msg ? zstrm->msg : deflate_zstrerror(deflate_zerrno));
717
718 errno = EIO;
719 return -1;
720 }
721
722 datalen = deflate_zbufsz - zstrm->avail_out;
723
724 while (datalen > 0) {
725 pr_signals_handle();
726
727 if (deflate_next_netio_write != NULL) {
728 res = (deflate_next_netio_write)(nstrm,
729 (char *) (deflate_zbuf + offset), datalen);
730
731 } else {
732 res = write(nstrm->strm_fd, deflate_zbuf + offset, datalen);
733 }
734
735 if (res < 0) {
736 if (errno == EINTR ||
737 errno == EAGAIN) {
738 /* The socket might be busy, especially if the peer is a bit
739 * slow in reading data from it.
740 */
741 pr_signals_handle();
742 continue;
743 }
744
745 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
746 "error writing to socket %d: %s", nstrm->strm_fd, strerror(errno));
747 return -1;
748 }
749
750 /* Manually adjust the "raw" bytes counter, so that it will be
751 * accurate for %O logging.
752 */
753 session.total_raw_out += res;
754
755 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
756 "wrote %d (of %lu) bytes of compressed of data to socket %d", res,
757 (unsigned long) datalen, nstrm->strm_fd);
758
759 /* Watch out for short writes */
760 if ((size_t) res == datalen) {
761 zstrm->next_out = deflate_zbuf;
762 zstrm->avail_out = deflate_zbufsz;
763 break;
764
765 } else {
766 offset += res;
767 datalen -= res;
768 }
769 }
770
771 /* Manually adjust the "raw" bytes in counter, so that it will
772 * be accurate for %O logging.
773 *
774 * We subtract the number we are returning here, since our return
775 * value will simply be added back to the counter in pr_netio_write().
776 * And if our subtraction causes an underflow, it's still OK since
777 * the subsequent addition will overflow, and get the value back to
778 * what it should be.
779 */
780
781 res = (buflen - zstrm->avail_in);
782 session.total_raw_out -= res;
783
784 pr_trace_msg(trace_channel, 9, "write: returning %d for %lu bytes",
785 res, (unsigned long) buflen);
786 return res;
787 }
788
789 return write(nstrm->strm_fd, buf, buflen);
790 }
791
792 /* Configuration handlers
793 */
794
795 /* usage: DeflateEngine on|off */
set_deflateengine(cmd_rec * cmd)796 MODRET set_deflateengine(cmd_rec *cmd) {
797 int bool;
798 config_rec *c;
799
800 CHECK_ARGS(cmd, 1);
801 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
802
803 bool = get_boolean(cmd, 1);
804 if (bool == -1) {
805 CONF_ERROR(cmd, "expected Boolean parameter");
806 }
807
808 c = add_config_param(cmd->argv[0], 1, NULL);
809 c->argv[0] = pcalloc(c->pool, sizeof(unsigned int));
810 *((unsigned int *) c->argv[0]) = bool;
811
812 return PR_HANDLED(cmd);
813 }
814
815 /* usage: DeflateLog path|"none" */
set_deflatelog(cmd_rec * cmd)816 MODRET set_deflatelog(cmd_rec *cmd) {
817 char *path;
818
819 CHECK_ARGS(cmd, 1);
820 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
821
822 path = cmd->argv[1];
823 if (pr_fs_valid_path(path) < 0) {
824 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": ", path, " is not a valid path",
825 NULL));
826 }
827
828 add_config_param_str(cmd->argv[0], 1, path);
829 return PR_HANDLED(cmd);
830 }
831
832 /* Command handlers
833 */
834
deflate_opts(cmd_rec * cmd)835 MODRET deflate_opts(cmd_rec *cmd) {
836 if (deflate_engine == FALSE) {
837 return PR_DECLINED(cmd);
838 }
839
840 if (cmd->argc < 3) {
841 return PR_DECLINED(cmd);
842 }
843
844 if (strcasecmp(cmd->argv[1], "Z") == 0) {
845
846 /* Twiddle the requested ZLIB parameters. */
847
848 if (cmd->argc == 3) {
849 /* If no key/value pairs were given, reset the deflate parameters
850 * to their default settings.
851 */
852 deflate_compression_level = MOD_DEFLATE_DEFAULT_COMPRESS_LEVEL;
853 deflate_mem_level = MOD_DEFLATE_DEFAULT_MEM_LEVEL;
854 deflate_strategy = MOD_DEFLATE_DEFAULT_STRATEGY;
855 deflate_window_bits = MOD_DEFLATE_DEFAULT_WINDOW_BITS;
856
857 pr_response_add(R_200, _("%s OK"), (char *) cmd->argv[0]);
858 return PR_HANDLED(cmd);
859
860 } else {
861 register unsigned int i;
862
863 if (cmd->argc % 2 != 0) {
864 pr_response_add_err(R_501, _("Bad number of parameters"));
865
866 pr_cmd_set_errno(cmd, EINVAL);
867 errno = EINVAL;
868 return PR_ERROR(cmd);
869 }
870
871 for (i = 2; i < cmd->argc; i += 2) {
872 char *key, *val;
873
874 key = cmd->argv[i];
875 val = cmd->argv[i+1];
876
877 if (strcasecmp(key, "blocksize") == 0 ||
878 strcasecmp(key, "engine") == 0) {
879 pr_response_add_err(R_501, _("%s: unsupported MODE Z option: %s"),
880 (char *) cmd->argv[0], key);
881
882 pr_cmd_set_errno(cmd, ENOSYS);
883 errno = ENOSYS;
884 return PR_ERROR(cmd);
885
886 } else if (strcasecmp(key, "level") == 0) {
887 int level;
888
889 level = atoi(val);
890 if (level < 0 ||
891 level > 9) {
892 pr_response_add_err(R_501, _("%s: bad MODE Z option value: %s %s"),
893 (char *) cmd->argv[0], key, val);
894
895 pr_cmd_set_errno(cmd, EINVAL);
896 errno = EINVAL;
897 return PR_ERROR(cmd);
898 }
899
900 deflate_compression_level = level;
901
902 } else {
903 pr_response_add_err(R_501, _("%s: unknown MODE Z option: %s"),
904 (char *) cmd->argv[0], key);
905
906 pr_cmd_set_errno(cmd, EINVAL);
907 errno = EINVAL;
908 return PR_ERROR(cmd);
909 }
910 }
911 }
912
913 pr_response_add(R_200, _("OPTS MODE Z OK"));
914 return PR_HANDLED(cmd);
915 }
916
917 return PR_DECLINED(cmd);
918 }
919
deflate_mode(cmd_rec * cmd)920 MODRET deflate_mode(cmd_rec *cmd) {
921 char *mode;
922
923 if (deflate_engine == FALSE) {
924 return PR_DECLINED(cmd);
925 }
926
927 if (cmd->argc != 2) {
928 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
929 "declining MODE Z (wrong number of parameters: %d)", cmd->argc);
930 return PR_DECLINED(cmd);
931 }
932
933 mode = cmd->argv[1];
934 mode[0] = toupper(mode[0]);
935
936 if (mode[0] == 'Z') {
937 if (session.rfc2228_mech != NULL) {
938 if (strcasecmp(session.rfc2228_mech, "tls") != 0) {
939 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
940 "declining MODE Z (RFC2228 mechanism '%s' in effect)",
941 session.rfc2228_mech);
942 pr_log_debug(DEBUG2, MOD_DEFLATE_VERSION
943 ": declining MODE Z (RFC2228 mechanism '%s' in effect)",
944 session.rfc2228_mech);
945
946 pr_response_add_err(R_504, _("Unable to handle MODE Z at this time"));
947
948 pr_cmd_set_errno(cmd, EPERM);
949 errno = EPERM;
950 return PR_ERROR(cmd);
951 }
952 }
953
954 if (deflate_enabled == TRUE) {
955 pr_response_add(R_200, _("OK"));
956 return PR_HANDLED(cmd);
957 }
958
959 deflate_next_netio = pr_get_netio(PR_NETIO_STRM_DATA);
960 if (deflate_next_netio != NULL) {
961 /* If another module has registered a NetIO callback already (e.g.
962 * mod_tls), we want to leave it in place, but replace some (but not all)
963 * of its callbacks with our own.
964 *
965 * We cache copies/pointers of the original callbacks, for restoring
966 * later if requested.
967 */
968 pr_trace_msg(trace_channel, 9, "overriding existing %s NetIO callbacks",
969 deflate_next_netio->owner_name? deflate_next_netio->owner_name :
970 deflate_next_netio->owner->name);
971
972 deflate_next_netio_close = deflate_next_netio->close;
973 deflate_next_netio->close = deflate_netio_close_cb;
974
975 deflate_next_netio_open = deflate_next_netio->open;
976 deflate_next_netio->open = deflate_netio_open_cb;
977
978 deflate_next_netio_read = deflate_next_netio->read;
979 deflate_next_netio->read = deflate_netio_read_cb;
980
981 deflate_next_netio_shutdown = deflate_next_netio->shutdown;
982 deflate_next_netio->shutdown = deflate_netio_shutdown_cb;
983
984 deflate_next_netio_write = deflate_next_netio->write;
985 deflate_next_netio->write = deflate_netio_write_cb;
986
987 } else {
988 /* Need to install some sort of NetIO handlers here, to handle
989 * compression.
990 */
991 deflate_netio = pr_alloc_netio2(session.pool, &deflate_module, NULL);
992 deflate_netio->close = deflate_netio_close_cb;
993 deflate_netio->open = deflate_netio_open_cb;
994 deflate_netio->read = deflate_netio_read_cb;
995 deflate_netio->shutdown = deflate_netio_shutdown_cb;
996 deflate_netio->write = deflate_netio_write_cb;
997
998 if (pr_register_netio(deflate_netio, PR_NETIO_STRM_DATA) < 0) {
999 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
1000 "error registering netio: %s", strerror(errno));
1001 }
1002 }
1003
1004 deflate_enabled = TRUE;
1005
1006 pr_response_add(R_200, _("OK"));
1007 return PR_HANDLED(cmd);
1008
1009 } else {
1010 if (deflate_enabled) {
1011 /* Switch to some other transmission mode. Remove our NetIO. */
1012
1013 if (deflate_next_netio != NULL) {
1014 deflate_next_netio->close = deflate_next_netio_close;
1015 deflate_next_netio_close = NULL;
1016
1017 deflate_next_netio->open = deflate_next_netio_open;
1018 deflate_next_netio_open = NULL;
1019
1020 deflate_next_netio->read = deflate_next_netio_read;
1021 deflate_next_netio_read = NULL;
1022
1023 deflate_next_netio->shutdown = deflate_next_netio_shutdown;
1024 deflate_next_netio_shutdown = NULL;
1025
1026 deflate_next_netio->write = deflate_next_netio_write;
1027 deflate_next_netio_write = NULL;
1028
1029 deflate_next_netio = NULL;
1030
1031 } else {
1032 if (pr_unregister_netio(PR_NETIO_STRM_DATA) < 0) {
1033 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
1034 "error unregistering netio: %s", strerror(errno));
1035
1036 } else {
1037 (void) pr_log_writefile(deflate_logfd, MOD_DEFLATE_VERSION,
1038 "%s %s: unregistered netio", (char *) cmd->argv[0],
1039 (char *) cmd->argv[1]);
1040 }
1041
1042 if (deflate_netio != NULL) {
1043 destroy_pool(deflate_netio->pool);
1044 deflate_netio = NULL;
1045 }
1046 }
1047
1048 deflate_enabled = FALSE;
1049 }
1050 }
1051
1052 return PR_DECLINED(cmd);
1053 }
1054
1055 /* Event listeners
1056 */
1057
deflate_sess_reinit_ev(const void * event_data,void * user_data)1058 static void deflate_sess_reinit_ev(const void *event_data, void *user_data) {
1059 int res;
1060
1061 /* A HOST command changed the main_server pointer, reinitialize ourselves. */
1062
1063 pr_event_unregister(&deflate_module, "core.session-reinit",
1064 deflate_sess_reinit_ev);
1065
1066 deflate_engine = FALSE;
1067 pr_feat_remove("MODE Z");
1068 (void) close(deflate_logfd);
1069 deflate_logfd = -1;
1070
1071 res = deflate_sess_init();
1072 if (res < 0) {
1073 pr_session_disconnect(&deflate_module,
1074 PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
1075 }
1076 }
1077
1078 /* Initialization functions
1079 */
1080
deflate_init(void)1081 static int deflate_init(void) {
1082 pr_log_debug(DEBUG5, MOD_DEFLATE_VERSION ": using zlib " ZLIB_VERSION);
1083 return 0;
1084 }
1085
deflate_sess_init(void)1086 static int deflate_sess_init(void) {
1087 config_rec *c;
1088
1089 pr_event_register(&deflate_module, "core.session-reinit",
1090 deflate_sess_reinit_ev, NULL);
1091
1092 c = find_config(main_server->conf, CONF_PARAM, "DeflateEngine", FALSE);
1093 if (c &&
1094 *((unsigned int *) c->argv[0]) == TRUE) {
1095 deflate_engine = TRUE;
1096
1097 } else {
1098 return 0;
1099 }
1100
1101 /* Add a FEAT string indicating support of MODE Z. Note that, in the
1102 * future, other compression engines (e.g. bzip2) will need to be handled
1103 * here as well.
1104 */
1105 pr_feat_add("MODE Z");
1106
1107 c = find_config(main_server->conf, CONF_PARAM, "DeflateLog", FALSE);
1108 if (c &&
1109 strcasecmp(c->argv[0], "none") != 0) {
1110 int res, xerrno = 0;
1111
1112 pr_signals_block();
1113 PRIVS_ROOT
1114 res = pr_log_openfile(c->argv[0], &deflate_logfd, PR_LOG_SYSTEM_MODE);
1115 xerrno = errno;
1116 PRIVS_RELINQUISH
1117 pr_signals_unblock();
1118
1119 switch (res) {
1120 case -1:
1121 pr_log_pri(PR_LOG_NOTICE, MOD_DEFLATE_VERSION
1122 ": notice: unable to open DeflateLog '%s': %s",
1123 (char *) c->argv[0], strerror(xerrno));
1124 break;
1125
1126 case PR_LOG_WRITABLE_DIR:
1127 pr_log_pri(PR_LOG_WARNING, MOD_DEFLATE_VERSION
1128 ": notice: unable to use DeflateLog '%s': parent directory is "
1129 "world-writable", (char *) c->argv[0]);
1130 break;
1131
1132 case PR_LOG_SYMLINK:
1133 pr_log_pri(PR_LOG_WARNING, MOD_DEFLATE_VERSION
1134 ": notice: unable to use DeflateLog '%s': cannot log to a symlink",
1135 (char *) c->argv[0]);
1136 break;
1137 }
1138 }
1139
1140 /* Allocate the buffers which will be used for inflating/deflating data.
1141 * Look up the optimal transfer buffer size, and use a factor of 8.
1142 * Later, if needed, a larger buffer will be allocated when necessary.
1143 */
1144 if (deflate_zbuf == NULL) {
1145 deflate_zbufsz = pr_config_get_xfer_bufsz() * 8;
1146 deflate_zbuf_ptr = deflate_zbuf = pcalloc(session.pool, deflate_zbufsz);
1147 deflate_zbuflen = 0;
1148 }
1149
1150 if (deflate_rbuf == NULL) {
1151 deflate_rbufsz = pr_config_get_xfer_bufsz();
1152 deflate_rbuf = palloc(session.pool, deflate_rbufsz);
1153 deflate_rbuflen = 0;
1154 }
1155
1156 return 0;
1157 }
1158
1159 /* Module API tables
1160 */
1161
1162 static conftable deflate_conftab[] = {
1163 { "DeflateEngine", set_deflateengine, NULL },
1164 { "DeflateLog", set_deflatelog, NULL },
1165 { NULL }
1166 };
1167
1168 static cmdtable deflate_cmdtab[] = {
1169 { CMD, C_OPTS "_MODE", G_NONE, deflate_opts, FALSE, FALSE, CL_MISC },
1170 { CMD, C_MODE, G_NONE, deflate_mode, FALSE, FALSE, CL_MISC },
1171 { 0, NULL }
1172 };
1173
1174 module deflate_module = {
1175 NULL, NULL,
1176
1177 /* Module API version 2.0 */
1178 0x20,
1179
1180 /* Module name */
1181 "deflate",
1182
1183 /* Module configuration handler table */
1184 deflate_conftab,
1185
1186 /* Module command handler table */
1187 deflate_cmdtab,
1188
1189 /* Module authentication handler table */
1190 NULL,
1191
1192 /* Module initialization function */
1193 deflate_init,
1194
1195 /* Session initialization function */
1196 deflate_sess_init,
1197
1198 /* Module version */
1199 MOD_DEFLATE_VERSION
1200 };
1201