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